您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script to detect and report NSFW content on Uhmegle and auto-skip users after a set time.
// ==UserScript== // @name Uhmegle NSFW Reporter with Auto-Skip // @namespace Freebee1693 // @version 1.2.2-GitHub // @description A script to detect and report NSFW content on Uhmegle and auto-skip users after a set time. // @license Apache License 2.0 // @match https://uhmegle.com/video* // @grant none // @run-at document-end // ==/UserScript== const SHOW_INFO = true; const INFORM_OTHER = false; const AUTO_SKIP = false; const AUTO_SKIP_SECONDS = 5; const CLASSIFY_INTERVAL = 500; const onnxJs = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@latest/dist/ort.min.js'; const modelPath = 'https://cdn.flawcra.cc/open_nsfw.onnx'; const threshold = 0.7; let ortSession = null; let classifyInterval = null; let isClassificationStarting = false; // Flag to prevent multiple starts let modelLoaded = false; const activeClassifications = new Map(); let messageSent = false; // Flag to track if the big message has been sent let reported = false; let autoSkipTimeoutId = null; // To manage the auto-skip timer Date.prototype.addSecs = function (s) { this.setTime(this.getTime() + s * 1000); return this; }; (async function loadNsfwReporter() { await loadOrt(); await getModel(); hookRTCPeerConnection(); if (AUTO_SKIP) { setInterval(() => { if (!window.connected) { log('Reconnecting...'); window.pressSkip(false); } window.starting = 0; window.blockNext = false; localStorage.removeItem('faceOverlay'); localStorage.removeItem('lastImg'); document.querySelector('#faceOverlay')?.remove(); }, 500); } })(); async function loadOrt() { log('Loading ONNX Runtime Web...'); const script = document.createElement('script'); script.src = onnxJs; document.head.appendChild(script); await new Promise((resolve, reject) => { script.onload = resolve; script.onerror = reject; }); log('Loaded ONNX Runtime Web.'); } async function getModel() { log('Getting NSFW Detection Model...'); if (ortSession == null) { log('Loading NSFW Detection Model...'); while (!window.hasOwnProperty('ort')) { log('Waiting for ONNX Runtime Web...'); await sleep(500); } ortSession = await ort.InferenceSession.create(modelPath); modelLoaded = true; log('Loaded NSFW Detection Model.'); } return ortSession; } function hookRTCPeerConnection() { window.oRTCPeerConnection = window.oRTCPeerConnection || window.RTCPeerConnection; window.RTCPeerConnection = function (...args) { const pc = new window.oRTCPeerConnection(...args); pc._classifyStarted = false; pc.oaddIceCandidate = pc.addIceCandidate; pc.addIceCandidate = function (iceCandidate, ...rest) { if (iceCandidate == null) { return pc.oaddIceCandidate(iceCandidate, ...rest); } if (!pc._classifyStarted) { pc._classifyStarted = true; startClassification(); startAutoSkipTimer(); // Start the auto-skip timer } return pc.oaddIceCandidate(iceCandidate, ...rest); }; pc.addEventListener('connectionstatechange', () => { if (pc.connectionState === 'connected') { window.connected = true; messageSent = false; // Reset the messageSent flag reported = false; startClassification(); startAutoSkipTimer(); // Start the auto-skip timer upon connection } else if ( pc.connectionState === 'disconnected' || pc.connectionState === 'failed' || pc.connectionState === 'closed' ) { window.connected = false; stopClassification(); clearAutoSkipTimer(); // Clear the auto-skip timer when disconnected } }); return pc; }; } function startClassification() { if (classifyInterval || !modelLoaded || isClassificationStarting) return; isClassificationStarting = true; // Prevent multiple starts if (window.connected) { classify(); // Run the first classification immediately classifyInterval = setInterval(() => { if (window.connected) { classify(); } else { stopClassification(); // Ensure we stop the interval if disconnected } }, CLASSIFY_INTERVAL); } isClassificationStarting = false; // Reset the flag after starting } function stopClassification() { if (classifyInterval) { clearInterval(classifyInterval); classifyInterval = null; } isClassificationStarting = false; // Reset the flag activeClassifications.clear(); // Clear any active classifications } async function classify() { const id = window.connectionID; if (activeClassifications.has(id)) { console.log(`Classification already active for connectionID ${id}`); return; } activeClassifications.set(id, true); try { let imageData = await getImage(); if (!imageData) { log(`No image data for connectionID ${id}. Retrying...`); let attempts = 0; const maxAttempts = 5; while (!imageData && attempts < maxAttempts) { await sleep(500); imageData = await getImage(); attempts++; } if (!imageData) { log(`Failed to get image data after ${attempts} attempts for connectionID ${id}.`); return; } } const score = await runModel(imageData); if (score == null) { log(`Failed to get score for connectionID ${id}.`); return; } if (id !== window.connectionID) { log(`ConnectionID changed from ${id} to ${window.connectionID}. Aborting classify.`); return; } if (score >= threshold && !reported) { window.socket.send(JSON.stringify({ event: 'report', id: id })); log(`Reporting NSFW score of ${score}`); reported = true; // Immediately skip NSFW users log('NSFW content detected. Skipping user...'); skipUser(); return; } if (SHOW_INFO) { showInfo(score, threshold); } } finally { activeClassifications.delete(id); } } function skipUser() { clearAutoSkipTimer(); // Clear any existing auto-skip timer window.pressSkip(false); window.pressSkip(false); } function startAutoSkipTimer() { clearAutoSkipTimer(); // Ensure no existing timer is running if (AUTO_SKIP) { autoSkipTimeoutId = setTimeout(() => { if (window.connected) { log(`Auto-skip time (${AUTO_SKIP_SECONDS}s) reached. Skipping user...`); skipUser(); } }, AUTO_SKIP_SECONDS * 1000); } } function clearAutoSkipTimer() { if (autoSkipTimeoutId) { clearTimeout(autoSkipTimeoutId); autoSkipTimeoutId = null; } } async function getImage() { const remoteVideo = document.querySelector('#remoteVideo'); if (!remoteVideo) { log('Remote video element not found.'); return null; } const canvas = document.createElement('canvas'); canvas.width = 224; canvas.height = 224; const ctx = canvas.getContext('2d'); try { ctx.drawImage(remoteVideo, 0, 0, canvas.width, canvas.height); } catch (e) { log('Error drawing video frame: ' + e.message); return null; } const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); return imageData; } async function runModel(imageData) { try { const inputTensor = await preprocessImage(imageData); const feeds = { [ortSession.inputNames[0]]: inputTensor }; const results = await ortSession.run(feeds); const output = results[ortSession.outputNames[0]]; const nsfwScore = output.data[1]; const score = parseFloat(nsfwScore.toFixed(4)); return score; } catch (error) { console.error('Error running the model:', error); return null; } } async function preprocessImage(imageData) { const width = 224; const height = 224; const data = imageData.data; const input = new Float32Array(width * height * 3); for (let i = 0; i < width * height; i++) { const r = data[i * 4]; const g = data[i * 4 + 1]; const b = data[i * 4 + 2]; input[i * 3] = b - 104; input[i * 3 + 1] = g - 117; input[i * 3 + 2] = r - 123; } return new ort.Tensor('float32', input, [1, 224, 224, 3]); } function showInfo(score, threshold) { const messageInput = document.querySelector('.messageInput'); if (!messageInput) return; if (!messageSent) { const humanScore = `${(score * 100).toFixed(2)}%`; const humanThreshold = `${(threshold * 100).toFixed(2)}%`; messageSent = true; let msg = `User has NSFW score of ${humanScore}.`; if (score >= threshold) { msg = `${msg} Reporting...`; } log(msg); if(!INFORM_OTHER) return; const message = `Hi! 🚨 Please be aware that inappropriate content is not allowed on this platform. If detected, it may be reported. Your content has an NSFW score of ${humanScore}. Scores above ${humanThreshold} may be reported to keep the community safe. Monitoring will continue in the background. This is an automated message. If you believe this is a mistake, please ensure your camera is clear of any inappropriate content.${AUTO_SKIP ? "\n\nI'll be disconnecting in " + AUTO_SKIP_SECONDS + " seconds." : ""}`; messageInput.value = message; window.sendMessage(); } } function log(data) { console.log(data); addMessage(data); } function addMessage(msg) { const logbox = document.querySelector('#mainMessages'); const div = document.createElement('div'); div.setAttribute('class', 'information'); const p = document.createElement('p'); p.setAttribute('class', 'statuslog'); p.innerHTML = msg; div.appendChild(p); logbox.appendChild(div); } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } window.addEventListener('beforeunload', () => { stopClassification(); clearAutoSkipTimer(); });