Uhmegle Fixes 2

Bypass face detection in Uhmegle, removes afk timeouts, with improved notifications

// ==UserScript==
// @name         Uhmegle Fixes 2
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Bypass face detection in Uhmegle, removes afk timeouts, with improved notifications
// @author       Fizi
// @match        https://uhmegle.com/video*
// @license      MIT
// @grant        none
// @run-at       document-start
// ==/UserScript==

(() => {
  const CONFIG = {
    imageURL: 'https://i.imgur.com/ghjBrek.png',
    canvasSize: { width: 1280, height: 720 }
  };
  const injectWebSocketOverride = () => {
    const OriginalWebSocket = window.WebSocket;
    let reportPending = false;

    window.WebSocket = function (url, protocols) {
      const socket = new OriginalWebSocket(url, protocols);
      const frame = VideoFrameManager.getFrame();

      socket.send = function (data) {
        if (typeof data === 'string' && data.includes('image')) {
          const imageData = frame.toDataURL('image/jpeg').split(';base64,')[1];
          OriginalWebSocket.prototype.send.call(this, JSON.stringify({
            event: 'image',
            image: imageData
          }));

          NotificationManager.notify({
            title: 'Success',
            description: reportPending ? 'Report bypassed' : 'Camera check bypassed',
            type: 'success',
            duration: 3000
          });
          reportPending = false;
          return;
        }
        OriginalWebSocket.prototype.send.call(this, data);
      };

      socket.addEventListener('message', event => {
        if (event.data.includes('rimage')) {
          reportPending = true;
          NotificationManager.notify({
            title: 'Warning',
            description: 'Report detected - disconnecting',
            type: 'warning',
            duration: 5000
          });
          document.querySelector('.bottomButton.outlined.skipButton.noSelect.stop')?.click();
        }
      });

      return socket;
    };
  };
  injectWebSocketOverride();

  class NotificationManager {
    static #container = null;
    static #typeConfig = {
      info: { color: '#2196F3', icon: 'ℹ️' },
      success: { color: '#4CAF50', icon: '✅' },
      warning: { color: '#FF9800', icon: '⚠️' },
      error: { color: '#F44336', icon: '❌' }
    };

    static createContainer() {
      if (!this.#container) {
        this.#container = document.createElement('div');
        this.#container.id = 'notification-container';
        this.#container.style.cssText = 'position:fixed;z-index:9999;display:flex;flex-direction:column;max-width:350px;width:100%;top:20px;right:20px;align-items:flex-end;';
        document.body.appendChild(this.#container);
      }
      return this.#container;
    }

    static notify({ title = 'Notification', description = '', type = 'info', duration = 5000 }) {
      const container = this.createContainer();
      const notification = document.createElement('div');
      const config = this.#typeConfig[type];

      notification.style.cssText = `
        background-color:${config.color};color:white;border-radius:8px;padding:15px;
        margin:10px;box-shadow:0 4px 6px rgba(0,0,0,0.1);display:flex;align-items:center;
        gap:10px;position:relative;overflow:hidden;animation:slideIn 0.5s ease forwards;
      `;

      notification.innerHTML = `
        <div>${config.icon}</div>
        <div>
          <strong>${title}</strong>
          <div style="font-size:14px;margin-top:5px">${description}</div>
        </div>
        <div style="position:absolute;bottom:0;left:0;height:4px;background:rgba(255,255,255,0.5);
          width:100%;transform-origin:left;animation:progressBar ${duration}ms linear forwards;">
        </div>
      `;

      container.appendChild(notification);
      setTimeout(() => {
        notification.style.animation = 'slideOut 0.5s forwards';
        setTimeout(() => {
          notification.remove();
          if (!container.children.length) container.remove();
        }, 500);
      }, duration);
    }
  }

  class VideoFrameManager {
    static #canvas = null;
    static #fallbackCanvas = null;

    static async initialize() {
      try {
        this.#canvas = await this.#loadImage(CONFIG.imageURL);
      } catch (err) {
        console.error('Failed to load image:', err);
        NotificationManager.notify({
          title: 'Error',
          description: 'Failed to load image - using fallback frame',
          type: 'error',
          duration: 5000
        });
        this.#canvas = this.#createFallbackFrame();
      }
      this.#fallbackCanvas = this.#createFallbackFrame();
    }

    static #loadImage(url) {
      return new Promise((resolve, reject) => {
        const canvas = document.createElement('canvas');
        Object.assign(canvas, CONFIG.canvasSize);
        const ctx = canvas.getContext('2d');

        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => {
          ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
          resolve(canvas);
        };
        img.onerror = reject;
        img.src = url;
      });
    }

    static #createFallbackFrame() {
      const canvas = document.createElement('canvas');
      Object.assign(canvas, CONFIG.canvasSize);
      canvas.getContext('2d').fillRect(0, 0, canvas.width, canvas.height);
      return canvas;
    }

    static getFrame() {
      return this.#canvas || this.#fallbackCanvas;
    }
  }



  const initialize = async () => {
    await VideoFrameManager.initialize();

    window.calculateVariance = () => 1000;
    Object.defineProperties(window, {
      isModerator: { get: () => true, set: () => { } },
      blockNext: { get: () => false, set: () => { } },
      captureLocalVideoFrames: { value: () => VideoFrameManager.getFrame() }
    });

    window.setAfkTimer = () => { };
    clearTimeout(window.afkTimer);

    const style = document.createElement('style');
    style.textContent = `
      @keyframes slideIn { from{transform:translateX(100%);opacity:0} to{transform:translateX(0);opacity:1} }
      @keyframes slideOut { from{transform:translateX(0);opacity:1} to{transform:translateX(100%);opacity:0} }
      @keyframes progressBar { from{transform:scaleX(1)} to{transform:scaleX(0)} }
    `;
    document.head.appendChild(style);

    NotificationManager.notify({
      title: 'Uhmegle Fixes 2',
      description: 'Loaded successfully',
      type: 'success',
      duration: 5000
    });
  };

  initialize().catch(console.error);
})();