omoggle live psl + video loop + drag

real-time psl slider, video cam loop, draggable menu, api hook

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         omoggle live psl + video loop + drag
// @namespace    lol
// @version      9.0
// @description  real-time psl slider, video cam loop, draggable menu, api hook
// @match        https://omoggle.com/*
// @match        https://www.omoggle.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    let current_psl = 9.9;
    let videoStream = null;

    // -------- API INTERCEPTORS (fetch + xhr) ----------
    const oldFetch = window.fetch;
    window.fetch = function(...args) {
        let url = args[0];
        let opts = args[1] || {};
        if (typeof url === 'string' && (url.includes('/api/match/finalize') || url.includes('/api/ranked/finalize'))) {
            if (opts.body) {
                try {
                    let body = JSON.parse(opts.body);
                    if (body.psl !== undefined) body.psl = current_psl;
                    if (body.score !== undefined) body.score = current_psl;
                    if (body.rating !== undefined) body.rating = current_psl;
                    if (body.yourScore !== undefined) body.yourScore = current_psl;
                    opts.body = JSON.stringify(body);
                } catch(e) {}
            }
        }
        return oldFetch.apply(this, [url, opts]);
    };

    const XHR = XMLHttpRequest.prototype;
    const oldOpen = XHR.open;
    const oldSend = XHR.send;
    XHR.open = function(method, url, ...rest) {
        this._mog_url = url;
        return oldOpen.apply(this, [method, url, ...rest]);
    };
    XHR.send = function(body) {
        if (this._mog_url && (this._mog_url.includes('/api/match/finalize') || this._mog_url.includes('/api/ranked/finalize'))) {
            if (body && typeof body === 'string') {
                try {
                    let parsed = JSON.parse(body);
                    if (parsed.psl !== undefined) parsed.psl = current_psl;
                    if (parsed.score !== undefined) parsed.score = current_psl;
                    if (parsed.rating !== undefined) parsed.rating = current_psl;
                    body = JSON.stringify(parsed);
                } catch(e) {}
            }
        }
        return oldSend.call(this, body);
    };

    // -------- WAIT FOR PAGE THEN ADD MENU ----------
    window.addEventListener('DOMContentLoaded', () => {
        // create menu div
        let menu = document.createElement('div');
        menu.id = 'mogmenu';
        menu.style.cssText = 'position:fixed; bottom:20px; right:20px; background:#111; border:1px solid #f0f; color:#eee; font-family:monospace; font-size:13px; padding:10px; z-index:99999; width:240px; cursor:default;';
        menu.innerHTML = `
            <div id="mogHeader" style="font-weight:bold; margin-bottom:10px; text-align:center; cursor:move;">OMOGGLE TOOL (drag me)</div>
            <div>PSL: <span id="pslValue">9.9</span></div>
            <input type="range" id="pslSlider" min="0.1" max="9.9" step="0.01" value="9.9" style="width:100%; margin:5px 0;">
            <div style="margin-top:10px;">📹 fake cam (video loop)</div>
            <input type="file" id="camFile" accept="video/*" style="width:100%; margin:5px 0;">
            <div id="camStatus" style="color:#aaa; font-size:11px;">no video</div>
            <div id="apiLog" style="border-top:1px solid #333; margin-top:8px; padding-top:5px; font-size:10px;">api: idle</div>
        `;
        document.body.appendChild(menu);

        // draggable functionality
        let header = document.getElementById('mogHeader');
        let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
        header.onmousedown = dragMouseDown;
        function dragMouseDown(e) {
            e = e || window.event;
            e.preventDefault();
            pos3 = e.clientX;
            pos4 = e.clientY;
            document.onmouseup = closeDrag;
            document.onmousemove = elementDrag;
        }
        function elementDrag(e) {
            e = e || window.event;
            e.preventDefault();
            pos1 = pos3 - e.clientX;
            pos2 = pos4 - e.clientY;
            pos3 = e.clientX;
            pos4 = e.clientY;
            let top = menu.offsetTop - pos2;
            let left = menu.offsetLeft - pos1;
            if (top > 0) menu.style.top = top + 'px';
            if (left > 0) menu.style.left = left + 'px';
            menu.style.bottom = 'auto';
            menu.style.right = 'auto';
        }
        function closeDrag() {
            document.onmouseup = null;
            document.onmousemove = null;
        }

        // psl slider -> update display and global value
        let slider = document.getElementById('pslSlider');
        let pslSpan = document.getElementById('pslValue');
        slider.addEventListener('input', (e) => {
            let val = parseFloat(e.target.value).toFixed(2);
            pslSpan.innerText = val;
            current_psl = parseFloat(val);
            // instantly spoof any visible score on page
            spoofAllScores(current_psl);
            document.getElementById('apiLog').innerHTML = `api: set to ${current_psl}`;
        });

        // function to find all score elements and change them live
        function spoofAllScores(score) {
            // common selectors
            let selectors = ['.score-value', '.psl-score', '.your-score', '[data-score]', '.rating-number', '.mog-score'];
            for (let sel of selectors) {
                document.querySelectorAll(sel).forEach(el => {
                    if (el.innerText && !isNaN(parseFloat(el.innerText))) el.innerText = score;
                });
            }
            // aggressive: any element with a single decimal number between 0.1-9.9
            document.querySelectorAll('*').forEach(el => {
                if (el.children.length === 0 && el.innerText && el.innerText.trim().match(/^\d+\.\d$/)) {
                    let num = parseFloat(el.innerText);
                    if (num >= 0.1 && num <= 9.9) el.innerText = score;
                }
            });
        }

        // run spoof repeatedly in case omoggle updates DOM
        setInterval(() => {
            spoofAllScores(current_psl);
        }, 500);

        // camera: video file upload (loops)
        let fileInput = document.getElementById('camFile');
        let camStatus = document.getElementById('camStatus');
        fileInput.addEventListener('change', (e) => {
            let f = e.target.files[0];
            if (f && f.type.startsWith('video/')) {
                let url = URL.createObjectURL(f);
                let video = document.createElement('video');
                video.src = url;
                video.loop = true;
                video.muted = true;   // required for autoplay
                video.onloadeddata = () => {
                    video.play();
                    // replace camera stream
                    let stream = video.captureStream(); // works in Chrome/Edge
                    // find user's video element
                    let userVideo = null;
                    document.querySelectorAll('video').forEach(v => {
                        if (v.srcObject && v.srcObject.getVideoTracks) userVideo = v;
                    });
                    if (userVideo && userVideo.srcObject) {
                        let oldTracks = userVideo.srcObject.getTracks();
                        oldTracks.forEach(t => t.stop());
                        userVideo.srcObject = stream;
                        camStatus.innerText = 'video loaded (looping)';
                        camStatus.style.color = '#8f8';
                    } else {
                        // fallback: store stream for later when video appears
                        videoStream = stream;
                        camStatus.innerText = 'waiting for cam...';
                        let checkInterval = setInterval(() => {
                            let uv = document.querySelector('video[srcObject]');
                            if (uv) {
                                uv.srcObject = stream;
                                camStatus.innerText = 'video applied';
                                clearInterval(checkInterval);
                            }
                        }, 500);
                    }
                };
            } else {
                camStatus.innerText = 'not a video file';
                camStatus.style.color = '#f88';
            }
        });

        // initial spoof
        spoofAllScores(9.9);
    });
})();