Website Data Cleaner

One-click clear current website data(localStorage/Cookie/Database etc.)

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Website Data Cleaner
// @namespace    http://tampermonkey.net/
// @version      1.3.0
// @description  One-click clear current website data(localStorage/Cookie/Database etc.)
// @description:zh-CN 自动识别系统语言,一键清除当前网站各类数据(localStorage/Cookie/数据库等)
// @author       ChiamZhang
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_openInTab
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // ================= 1. 语言包配置(统一管理中英文文本)=================
    const LANG_PACK = {
        // 中文配置
        zh: {
            menu: {
                clearAll: '🗑️ 清除当前网站所有数据',
                clearBasic: '📦 仅清除 localStorage + SessionStorage',
                clearCookie: '🍪 仅清除当前网站Cookie',
                clearDB: '🗄️ 仅清除 IndexedDB + Web SQL',
                feedback: 'Github 主页',
            },
            confirm: {
                clearAll: '⚠️ 确认清除当前网站所有数据?\n包含:localStorage、SessionStorage、Cookie、IndexedDB、Web SQL\n清除后不可恢复,登录状态会失效!',
                clearBasic: '确认清除当前网站的localStorage和SessionStorage?\n这会清除网站保存的本地设置和临时数据!',
                clearCookie: '确认清除当前网站的所有Cookie?\n这会导致登录状态失效,需要重新登录!',
                clearDB: '确认清除当前网站的IndexedDB和Web SQL数据库?\n这会清除网站保存的离线数据和缓存内容!'
            },
            notification: {
                clearAllSuccess: '✅ 当前网站所有数据清除成功!',
                clearAllPartial: '部分数据清除成功,部分数据可能未清除(详见控制台)',
                clearBasicSuccess: '✅ 基础存储数据清除成功!',
                clearCookieSuccess: '✅ Cookie清除成功!',
                clearDBSuccess: '✅ 数据库数据清除成功!',
                feedbackOpen: '已打开反馈页面,感谢你的建议!',
                error: '❌ 数据清除过程中发生错误',
                switchEnable: '%s已启用',
                switchDisable: '%s已禁用'
            },
            console: {
                init: '【网站数据清除工具】菜单已加载完成,可在油猴菜单中操作',
                clearLocalStorage: '[数据清除] localStorage 清除成功',
                clearSessionStorage: '[数据清除] sessionStorage 清除成功',
                clearCookie: '[数据清除] Cookie 清除成功(共%s个)',
                clearCookieFail: '[数据清除] Cookie 清除失败:%s',
                clearIndexedDB: '[数据清除] IndexedDB 清除完成(共%s个数据库)',
                clearIndexedDBBlocked: '[数据清除] IndexedDB %s 被占用(可能有其他标签页打开)',
                clearWebSQL: '[数据清除] Web SQL 清除完成(处理%s个匹配模式)',
                clearFail: '[数据清除%s] %s'
            }
        },
        // 英文配置
        en: {
            menu: {
                clearAll: '🗑️ Clear All Data of Current Website',
                clearBasic: '📦 Clear Only localStorage + SessionStorage',
                clearCookie: '🍪 Clear Only Current Website Cookies',
                clearDB: '🗄️ Clear Only IndexedDB + Web SQL',
                feedback: 'Project Link:Github Link',
            },
            confirm: {
                clearAll: '⚠️ Confirm to clear all data of current website?\nIncluded: localStorage, SessionStorage, Cookies, IndexedDB, Web SQL\nIrreversible, login status will be lost!',
                clearBasic: 'Confirm to clear localStorage and SessionStorage of current website?\nThis will delete local settings and temporary data saved by the website!',
                clearCookie: 'Confirm to clear all cookies of current website?\nLogin status will be lost, need to re-login!',
                clearDB: 'Confirm to clear IndexedDB and Web SQL of current website?\nThis will delete offline data and cache content saved by the website!'
            },
            notification: {
                clearAllSuccess: '✅ All data of current website cleared successfully!',
                clearAllPartial: 'Partial data cleared successfully, some data may not be deleted (see console for details)',
                clearBasicSuccess: '✅ Basic storage data cleared successfully!',
                clearCookieSuccess: '✅ Cookies cleared successfully!',
                clearDBSuccess: '✅ Database data cleared successfully!',
                feedbackOpen: 'Feedback page opened, thank you for your suggestion!',
                error: '❌ Error occurred during data cleaning',
                switchEnable: '%s enabled',
                switchDisable: '%s disabled'
            },
            console: {
                init: '[Website Data Cleaner] Menu loaded successfully, operate via Tampermonkey menu',
                clearLocalStorage: '[Data Cleanup] localStorage cleared successfully',
                clearSessionStorage: '[Data Cleanup] sessionStorage cleared successfully',
                clearCookie: '[Data Cleanup] Cookies cleared successfully (total %s)',
                clearCookieFail: '[Data Cleanup] Cookie cleanup failed: %s',
                clearIndexedDB: '[Data Cleanup] IndexedDB cleaned up (total %s databases)',
                clearIndexedDBBlocked: '[Data Cleanup] IndexedDB %s is occupied (other tabs may be open)',
                clearWebSQL: '[Data Cleanup] Web SQL cleaned up (processed %s patterns)',
                clearFail: '[Data Cleanup%s] %s'
            }
        }
    };

    // ================= 2. 自动检测系统语言 =================
    let currentLang = 'en'; // 默认英文
    const userLang = navigator.language || navigator.userLanguage; // 获取浏览器/系统语言

    // 判断是否为中文环境(支持 zh-CN、zh-TW、zh-HK 等)
    if (userLang.toLowerCase().startsWith('zh')) {
        currentLang = 'zh';
    }

    // 获取当前语言对应的文本(简化调用)
    const t = (path) => {
        const keys = path.split('.');
        return keys.reduce((obj, key) => obj?.[key] || path, LANG_PACK[currentLang]);
    };

    // ================= 3. 全局变量 =================
    const menuId = []; // 存储菜单ID,用于后续注销
    // 菜单配置(关联语言包中的菜单名称)
    const menuAll = [
        ['menu_clearAll', t('menu.clearAll'), 'clearAllData', false],
        ['menu_clearBasic', t('menu.clearBasic'), 'clearBasicData', false],
        ['menu_clearCookie', t('menu.clearCookie'), 'clearOnlyCookie', false],
        ['menu_clearDB', t('menu.clearDB'), 'clearOnlyDB', false],
        ['menu_feedback', t('menu.feedback'), 'openFeedback', false]
    ];

    // ================= 4. 核心清除函数 =================
    /**
     * 清除localStorage
     */
    function clearLocalStorage() {
        try {
            localStorage.clear();
            console.log(t('console.clearLocalStorage'));
            return true;
        } catch (e) {
            console.error(t('console.clearCookieFail'), e);
            return false;
        }
    }

    /**
     * 清除sessionStorage
     */
    function clearSessionStorage() {
        try {
            sessionStorage.clear();
            console.log(t('console.clearSessionStorage'));
            return true;
        } catch (e) {
            console.error(t('console.clearCookieFail'), e);
            return false;
        }
    }

    /**
     * 清除当前网站的Cookie
     */
    function clearCookies() {
        try {
            const cookies = document.cookie.split(';').filter(c => c.trim());
            const domain = window.location.hostname;

            // 兼容不同子域名和路径的Cookie清除
            cookies.forEach(cookie => {
                const eqPos = cookie.indexOf('=');
                const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : cookie.trim();

                // 多场景清除确保生效
                document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}; SameSite=None; Secure`;
                document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.${domain}; SameSite=None; Secure`;
                document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=None; Secure`;
            });

            console.log(t('console.clearCookie'), cookies.length);
            return true;
        } catch (e) {
            console.error(t('console.clearCookieFail'), e);
            return false;
        }
    }

    /**
     * 清除IndexedDB
     */
    async function clearIndexedDB() {
        try {
            if (!window.indexedDB) return true;

            const databases = await indexedDB.databases();
            if (databases.length === 0) return true;

            for (const db of databases) {
                await new Promise((resolve) => {
                    const request = indexedDB.deleteDatabase(db.name);
                    request.onsuccess = () => resolve(true);
                    request.onerror = (err) => {
                        console.warn(t('console.clearIndexedDBBlocked'), db.name, err);
                        resolve(false);
                    };
                    request.onblocked = () => {
                        console.warn(t('console.clearIndexedDBBlocked'), db.name);
                        resolve(false);
                    };
                });
            }

            console.log(t('console.clearIndexedDB'), databases.length);
            return true;
        } catch (e) {
            console.error(t('console.clearCookieFail'), e);
            return false;
        }
    }

    /**
     * 清除Web SQL
     */
    function clearWebSQL() {
        try {
            if (!window.openDatabase) return true;

            // 遍历常见的Web SQL数据库名称模式
            const dbNamePatterns = ['web sql', 'site_', 'app_', 'local_', 'data_', 'db_'];
            let clearedCount = 0;

            dbNamePatterns.forEach(pattern => {
                try {
                    const db = openDatabase(`temp_${pattern}`, '1.0', 'Temporary DB for deletion', 1024 * 1024);
                    db.transaction(tx => {
                        tx.executeSql('DROP TABLE IF EXISTS main');
                        clearedCount++;
                    });
                } catch (e) {}
            });

            console.log(t('console.clearWebSQL'), clearedCount);
            return true;
        } catch (e) {
            console.error(t('console.clearCookieFail'), e);
            return true;
        }
    }

    // ================= 5. 功能入口函数 =================
    /**
     * 显示操作结果通知
     * @param {string} messageKey 语言包中的消息键名
     * @param {boolean} success 是否成功
     * @param {Array} args 消息格式化参数(可选)
     */
    function showResult(messageKey, success = true, args = []) {
        let message = t(`notification.${messageKey}`);
        // 格式化消息(支持占位符 %s)
        if (args.length > 0) {
            args.forEach(arg => {
                message = message.replace(/%s/, arg);
            });
        }

        // 优先使用浏览器通知API
        if (Notification.permission === 'granted') {
            new Notification(
                currentLang === 'zh' ? '网站数据清除工具' : 'Website Data Cleaner',
                { body: message }
            );
        } else if (Notification.permission !== 'denied') {
            Notification.requestPermission().then(perm => {
                if (perm === 'granted') {
                    new Notification(
                        currentLang === 'zh' ? '网站数据清除工具' : 'Website Data Cleaner',
                        { body: message }
                    );
                }
            });
        }

        // 控制台打印详细信息
        console.log(t('console.clearFail'), success ? 'Success' : 'Fail', message);

        // 页面顶部临时提示
        const toast = document.createElement('div');
        toast.style.cssText = `
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            padding: 12px 24px;
            border-radius: 4px;
            background: ${success ? '#4CAF50' : '#f44336'};
            color: white;
            font-size: 14px;
            z-index: 999999;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            opacity: 0;
            transition: opacity 0.3s ease;
        `;
        toast.textContent = message;
        document.body.appendChild(toast);

        setTimeout(() => toast.style.opacity = '1', 10);
        setTimeout(() => {
            toast.style.opacity = '0';
            setTimeout(() => document.body.removeChild(toast), 300);
        }, 3000);
    }

    /**
     * 清除所有数据(完整模式)
     */
    async function clearAllData() {
        if (!confirm(t('confirm.clearAll'))) {
            return;
        }

        try {
            const results = [
                clearLocalStorage(),
                clearSessionStorage(),
                clearCookies(),
                await clearIndexedDB(),
                clearWebSQL()
            ];

            const hasFailure = results.some(res => !res);
            if (hasFailure) {
                showResult('clearAllPartial', false);
            } else {
                showResult('clearAllSuccess', true);
                // 可选:清除后刷新页面(取消注释启用)
                // if (confirm(currentLang === 'zh' ? '是否刷新页面使清除生效?' : 'Refresh page to take effect?')) location.reload();
            }
        } catch (e) {
            showResult('error', false);
            console.error(t('console.clearFail'), 'Error', e);
        }
    }

    /**
     * 仅清除基础存储(localStorage + SessionStorage)
     */
    function clearBasicData() {
        if (!confirm(t('confirm.clearBasic'))) {
            return;
        }

        const res1 = clearLocalStorage();
        const res2 = clearSessionStorage();

        if (res1 && res2) {
            showResult('clearBasicSuccess', true);
        } else {
            showResult('error', false);
        }
    }

    /**
     * 仅清除Cookie
     */
    function clearOnlyCookie() {
        if (!confirm(t('confirm.clearCookie'))) {
            return;
        }

        const res = clearCookies();
        if (res) {
            showResult('clearCookieSuccess', true);
        } else {
            showResult('error', false);
        }
    }

    /**
     * 仅清除数据库(IndexedDB + Web SQL)
     */
    async function clearOnlyDB() {
        if (!confirm(t('confirm.clearDB'))) {
            return;
        }

        const res1 = await clearIndexedDB();
        const res2 = clearWebSQL();

        if (res1 && res2) {
            showResult('clearDBSuccess', true);
        } else {
            showResult('clearAllPartial', false);
        }
    }

    /**
     * 反馈功能
     */
    function openFeedback() {
        GM_openInTab('https://github.com/ChiamZhang/WebsiteDataCleaner', {
            active: true,
            insert: true,
            setParent: true
        });
        showResult('feedbackOpen', true);
    }

    // ================= 6. 菜单注册函数 =================
    /**
     * 注册油猴菜单(根据当前语言显示对应名称)
     */
    function registerMenuCommand() {
        // 先注销已存在的菜单,避免重复
        if (menuId.length > 0) {
            menuId.forEach(id => {
                try { GM_unregisterMenuCommand(id); } catch (e) {}
            });
            menuId.length = 0; // 清空数组
        }

        // 循环注册菜单
        for (let i = 0; i < menuAll.length; i++) {
            const [menuKey, menuName, funcName, menuState] = menuAll[i];

            // 从存储中读取菜单状态(如果有)
            menuAll[i][3] = GM_getValue(menuKey, menuState);

            // 绑定对应的功能函数
            const funcMap = {
                clearAllData,
                clearBasicData,
                clearOnlyCookie,
                clearOnlyDB,
                openFeedback
            };
            const targetFunc = funcMap[funcName] || (() => {});

            // 注册菜单
            menuId[i] = GM_registerMenuCommand(menuName, targetFunc);
        }


    }

    /**
     * 菜单开关状态切换(预留功能)
     * @param {boolean} currentState 当前状态
     * @param {string} menuKey 菜单ID
     * @param {string} menuDesc 菜单描述
     */
    function menuSwitch(currentState, menuKey, menuDesc) {
        const newState = !currentState;
        GM_setValue(menuKey, newState);
        showResult(newState ? 'switchEnable' : 'switchDisable', true, [menuDesc]);
        registerMenuCommand(); // 重新注册菜单更新状态显示
    }

    // ================= 7. 初始化 =================
    // 检查通知权限(可选,提升用户体验)
    if (Notification.permission !== 'granted' && Notification.permission !== 'denied') {
        console.log(currentLang === 'zh'
            ? '[数据清除工具] 可在浏览器设置中开启通知权限,获取清除结果提醒'
            : '[Website Data Cleaner] Enable notification permission in browser settings for cleanup result alerts'
        );
    }

    // 注册菜单
    if (menuId.length < 4) {
        registerMenuCommand();
    }

    // 控制台初始化提示
    console.log(t('console.init'));
})();