Instagram Ghost Mode

Ghost mode for Instagram: block story views & DM read receipts; draggable toggle with memory, lock/unlock, notifications, and keyboard shortcut

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Instagram Ghost Mode
// @namespace    https://yasser-ghostmode.example
// @version      2.5
// @description  Ghost mode for Instagram: block story views & DM read receipts; draggable toggle with memory, lock/unlock, notifications, and keyboard shortcut
// @author       Yasser
// @license      Copyright (c) 2025 Yasser - All Rights Reserved
// @match        https://www.instagram.com/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // --- State ---
    let ghostMode = JSON.parse(localStorage.getItem('IG_GHOST_MODE_ENABLED')) || false;
    let locked = JSON.parse(localStorage.getItem('IG_GHOST_LOCKED')) || false;

    // --- Utility: Notification ---
    function showNotice(msg, color) {
        const box = document.createElement('div');
        box.innerText = msg;
        box.style.position = 'fixed';
        box.style.top = '20px';
        box.style.left = '50%';
        box.style.transform = 'translateX(-50%)';
        box.style.padding = '10px 20px';
        box.style.background = color;
        box.style.color = '#fff';
        box.style.fontWeight = 'bold';
        box.style.fontSize = '14px';
        box.style.borderRadius = '8px';
        box.style.zIndex = 2147483647;
        box.style.opacity = '0.9';
        box.style.transition = 'opacity 0.5s';
        document.body.appendChild(box);
        setTimeout(() => {
            box.style.opacity = '0';
            setTimeout(() => box.remove(), 500);
        }, 1500);
    }

    // --- Core patch: block reads/views ---
    const open = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function (method, url) {
        if (ghostMode && typeof url === 'string') {
            if (url.includes('/seen') || url.includes('/read')) {
                console.log('[GhostMode] blocked request:', url);
                return; // block story seen / message read
            }
        }
        return open.apply(this, arguments);
    };

    // --- Floating Button ---
    const btn = document.createElement('div');
    btn.id = 'ghostModeBtn';
    btn.innerText = ghostMode ? '👻' : '❌';
    btn.style.position = 'fixed';
    btn.style.background = ghostMode ? 'green' : 'red';
    btn.style.color = '#fff';
    btn.style.padding = '10px 15px';
    btn.style.fontSize = '14px';
    btn.style.fontWeight = 'bold';
    btn.style.borderRadius = '10px';
    btn.style.cursor = locked ? 'default' : 'grab';
    btn.style.zIndex = 2147483647;
    btn.style.boxShadow = '0 2px 8px rgba(0,0,0,.3)';
    btn.style.opacity = '0.5';

    // Hover effect
    btn.onmouseenter = () => { btn.style.opacity = '1'; };
    btn.onmouseleave = () => { btn.style.opacity = '0.5'; };

    // Restore saved position
    const savedPos = JSON.parse(localStorage.getItem('IG_GHOST_BTN_POS')) || null;
    if (savedPos && Number.isFinite(savedPos.x) && Number.isFinite(savedPos.y)) {
        btn.style.left = savedPos.x + 'px';
        btn.style.top = savedPos.y + 'px';
    } else {
        btn.style.bottom = '20px';
        btn.style.right = '20px';
    }
    document.body.appendChild(btn);

    // --- Dragging Logic ---
    let isDragging = false, offsetX, offsetY;

    btn.addEventListener('mousedown', e => {
        if (locked || e.button !== 0) return; // only left click drag if unlocked
        isDragging = true;
        offsetX = e.clientX - btn.offsetLeft;
        offsetY = e.clientY - btn.offsetTop;
        btn.style.cursor = 'grabbing';
        e.preventDefault();
    });

    document.addEventListener('mousemove', e => {
        if (isDragging) {
            btn.style.left = (e.clientX - offsetX) + 'px';
            btn.style.top = (e.clientY - offsetY) + 'px';
            btn.style.right = 'auto';
            btn.style.bottom = 'auto';
        }
    });

    document.addEventListener('mouseup', e => {
        if (isDragging) {
            isDragging = false;
            btn.style.cursor = 'grab';
            localStorage.setItem('IG_GHOST_BTN_POS', JSON.stringify({ x: btn.offsetLeft, y: btn.offsetTop }));
        }
    });

    // --- Left click = toggle ---
    btn.addEventListener('click', e => {
        if (isDragging || e.button !== 0) return; // ignore drag or non-left clicks
        toggleGhostMode();
    });

    // --- Right click = lock/unlock ---
    btn.addEventListener('contextmenu', e => {
        e.preventDefault();
        locked = !locked;
        localStorage.setItem('IG_GHOST_LOCKED', JSON.stringify(locked));
        btn.style.cursor = locked ? 'default' : 'grab';
        showNotice(locked ? 'Button Locked' : 'Button Unlocked', locked ? 'blue' : 'orange');
    });

    // --- Keyboard shortcut (G = toggle) ---
    document.addEventListener('keydown', e => {
        if (e.key.toLowerCase() === 'g' && !e.repeat) {
            toggleGhostMode();
        }
    });

    // --- Toggle Function ---
    function toggleGhostMode() {
        ghostMode = !ghostMode;
        localStorage.setItem('IG_GHOST_MODE_ENABLED', JSON.stringify(ghostMode));
        btn.innerText = ghostMode ? '👻' : '❌';
        btn.style.background = ghostMode ? 'green' : 'red';
        showNotice(ghostMode ? 'Ghost Mode Enabled' : 'Ghost Mode Disabled', ghostMode ? 'green' : 'red');
    }
})();