Omoggle Simple Spoof (Score + Camera)

Visual score spoof (10.0) + camera image replacement – works even after updates

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Omoggle Simple Spoof (Score + Camera)
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Visual score spoof (10.0) + camera image replacement – works even after updates
// @match        *://*.omoggle.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
  'use strict';

  // ======================= SCORE SPOOF (visual + finalize) =======================
  // Force your displayed score to always be 10.0
  function fixScoreText() {
    const scoreSelector = 'span.font-mono.font-black.text-white.drop-shadow-md, .score-value, [class*="score"]';
    const observer = new MutationObserver(() => {
      document.querySelectorAll(scoreSelector).forEach(el => {
        const txt = el.innerText.trim();
        if (/^\d+(\.\d)?$/.test(txt) && parseFloat(txt) !== 10.0) {
          el.innerText = '10.0';
        }
      });
    });
    observer.observe(document.body, { childList: true, subtree: true, characterData: true });
  }

  // Intercept finalize fetch to set opponent score low (9.8)
  const origFetch = window.fetch;
  window.fetch = function(url, options) {
    if (typeof url === 'string' && (url.includes('/api/match/finalize') || url.includes('/api/ranked/finalize'))) {
      if (options && options.body) {
        try {
          const body = JSON.parse(options.body);
          // Set your score to 10.0, opponent to 9.8
          if (body.selfScore !== undefined) body.selfScore = 10.0;
          if (body.opponentScore !== undefined) body.opponentScore = 9.8;
          if (body.myScore !== undefined) body.myScore = 10.0;
          if (body.theirScore !== undefined) body.theirScore = 9.8;
          options.body = JSON.stringify(body);
        } catch(e) {}
      }
    }
    return origFetch.call(this, url, options);
  };

  // Run score spoof when DOM ready
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', fixScoreText);
  } else {
    fixScoreText();
  }

  // ======================= CAMERA SPOOF (static image from file) =======================
  let cameraActive = false;
  let cameraStream = null;
  let imageElement = null;
  const STORAGE_KEY = 'omoggle_cam_image';

  // Create a canvas that draws the selected image
  let canvas = null;
  let ctx = null;
  let animationId = null;

  function initCanvas() {
    if (canvas) return;
    canvas = document.createElement('canvas');
    canvas.width = 640;
    canvas.height = 480;
    ctx = canvas.getContext('2d');
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, 640, 480);
  }

  function drawImage(img) {
    if (!ctx) return;
    ctx.clearRect(0, 0, 640, 480);
    const scale = Math.max(640 / img.width, 480 / img.height);
    const dx = (640 - img.width * scale) / 2;
    const dy = (480 - img.height * scale) / 2;
    ctx.drawImage(img, dx, dy, img.width * scale, img.height * scale);
  }

  function loadImageFromDataURL(dataURL) {
    const img = new Image();
    img.onload = () => {
      imageElement = img;
      drawImage(img);
      if (cameraActive && canvas) {
        // Update the stream if active
        if (cameraStream) {
          const newStream = canvas.captureStream(30);
          const newTrack = newStream.getVideoTracks()[0];
          const oldTracks = cameraStream.getVideoTracks();
          oldTracks.forEach(t => t.stop());
          cameraStream = newStream;
          // Replace in all video elements using this stream
          document.querySelectorAll('video').forEach(vid => {
            if (vid.srcObject === cameraStream) vid.srcObject = newStream;
          });
        }
      }
    };
    img.src = dataURL;
  }

  function loadSavedImage() {
    const saved = localStorage.getItem(STORAGE_KEY);
    if (saved) loadImageFromDataURL(saved);
  }

  function saveImageFromFile(file) {
    const reader = new FileReader();
    reader.onload = e => {
      localStorage.setItem(STORAGE_KEY, e.target.result);
      loadImageFromDataURL(e.target.result);
    };
    reader.readAsDataURL(file);
  }

  // Override getUserMedia to return our canvas stream when camera spoof is active
  const originalGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
  navigator.mediaDevices.getUserMedia = async function(constraints) {
    if (cameraActive && constraints && constraints.video) {
      if (!canvas) initCanvas();
      if (imageElement) drawImage(imageElement);
      if (!cameraStream) cameraStream = canvas.captureStream(30);
      // If audio requested, combine real audio with fake video
      if (constraints.audio) {
        try {
          const audioStream = await originalGetUserMedia({ audio: constraints.audio });
          const tracks = [...cameraStream.getVideoTracks(), ...audioStream.getAudioTracks()];
          return new MediaStream(tracks);
        } catch(e) {
          return cameraStream;
        }
      }
      return cameraStream;
    }
    return originalGetUserMedia(constraints);
  };

  // Also patch RTCPeerConnection to ensure track replacement
  const origAddTrack = RTCPeerConnection.prototype.addTrack;
  RTCPeerConnection.prototype.addTrack = function(track, ...streams) {
    if (cameraActive && track.kind === 'video' && cameraStream) {
      const fakeTrack = cameraStream.getVideoTracks()[0];
      if (fakeTrack) return origAddTrack.call(this, fakeTrack, ...streams);
    }
    return origAddTrack.call(this, track, ...streams);
  };

  // ======================= UI (mobile friendly) =======================
  function buildUI() {
    if (document.getElementById('simple-spoof-ui')) return;

    const toggleBtn = document.createElement('button');
    toggleBtn.id = 'simple-spoof-toggle';
    toggleBtn.innerText = '📷';
    toggleBtn.style.cssText = `
      position: fixed;
      bottom: 20px;
      right: 20px;
      width: 50px;
      height: 50px;
      border-radius: 25px;
      background: #00ff88;
      border: none;
      font-size: 24px;
      z-index: 999999;
      cursor: pointer;
      box-shadow: 0 2px 10px black;
    `;
    document.body.appendChild(toggleBtn);

    const panel = document.createElement('div');
    panel.id = 'simple-spoof-ui';
    panel.style.cssText = `
      position: fixed;
      bottom: 80px;
      right: 20px;
      width: 240px;
      background: #111;
      border: 2px solid #00ff88;
      border-radius: 12px;
      padding: 12px;
      color: white;
      font-family: monospace;
      z-index: 999998;
      display: none;
      flex-direction: column;
      gap: 10px;
    `;
    panel.innerHTML = `
      <div style="display:flex; justify-content:space-between; align-items:center;">
        <span style="color:#00ff88;">📷 Camera Spoof</span>
        <label style="display:flex; align-items:center; gap:6px;">
          <span>OFF</span>
          <input type="checkbox" id="camToggleCheckbox">
        </label>
      </div>
      <button id="choosePhotoBtn" style="background:#333; border:1px solid #00ff88; border-radius:8px; padding:6px; color:white;">Select Photo</button>
      <input type="file" id="photoInput" accept="image/*" style="display:none;">
      <div id="camStatus" style="font-size:11px; color:#aaa;">No photo loaded</div>
      <div style="font-size:10px; border-top:1px solid #333; margin-top:5px; padding-top:5px;">
        Score: <span style="color:#00ff88;">10.0 (you)</span> | Opp: 9.8
      </div>
    `;
    document.body.appendChild(panel);

    const checkbox = document.getElementById('camToggleCheckbox');
    const statusDiv = document.getElementById('camStatus');
    const chooseBtn = document.getElementById('choosePhotoBtn');
    const fileInput = document.getElementById('photoInput');

    checkbox.addEventListener('change', () => {
      cameraActive = checkbox.checked;
      const label = checkbox.parentElement.querySelector('span:first-child');
      if (cameraActive) {
        label.innerText = 'ON';
        if (!imageElement) loadSavedImage();
        statusDiv.innerText = 'Active – using ' + (imageElement ? 'photo' : 'default black');
      } else {
        label.innerText = 'OFF';
        statusDiv.innerText = 'Camera spoof off';
      }
    });

    chooseBtn.addEventListener('click', () => fileInput.click());
    fileInput.addEventListener('change', e => {
      if (e.target.files[0]) {
        saveImageFromFile(e.target.files[0]);
        statusDiv.innerText = 'Photo saved! Enable spoof.';
      }
    });

    toggleBtn.addEventListener('click', () => {
      const isVisible = panel.style.display === 'flex';
      panel.style.display = isVisible ? 'none' : 'flex';
    });

    // Load saved photo on startup
    loadSavedImage();
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', buildUI);
  } else {
    buildUI();
  }
})();