Clean Clipboard

ตรวจ clipboard ทุก 3 วิ, ทำงานเฉพาะเมื่อ tab โฟกัส, ถ้ามีข้อความไทยเกิน 100 ตัว → clean และคัดลอกกลับ (เลือกเก็บ format หรือไม่) + ตรวจจับข้อความใหม่

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Clean Clipboard
// @namespace    http://tampermonkey.net/
// @version      1.5
// @description  ตรวจ clipboard ทุก 3 วิ, ทำงานเฉพาะเมื่อ tab โฟกัส, ถ้ามีข้อความไทยเกิน 100 ตัว → clean และคัดลอกกลับ (เลือกเก็บ format หรือไม่) + ตรวจจับข้อความใหม่
// @author       You
// @match        https://*/*
// @grant        GM_setClipboard
// @license      MIT
// ==/UserScript==
/* eslint-disable no-multi-spaces */
(function () {
    'use strict';
    /** ================== CONFIG ================== */
    const CONFIG = {
        DEBUG: false,           // ปิดเปิดฟังก์ชันดีบัก
        THAI_LIMIT: 10,         // จำนวนขั้นต่ำของอักษรไทย
        CHINESE_LIMIT: 300,     // ถ้าจำนวนอักษรจีนเกินไม่ต้องทำงาน
        CHECK_INTERVAL: 1000,   // ตรวจเช็คทุกๆ x วินาที
        KEEP_FORMAT: false,     // true = เก็บ format, false = plain text only

        BEEP_FREQUENCY: 3000,   // Hz
        BEEP_DURATION: 0.3,     // s
        BEEP_VOLUME: 0.1,      // 0.0-1
        ENABLE_SOUND: true      // เปิดเสียงแจ้งเตือน
    };
    /* ================== STATE ================== */
    let audioCtx = null;
    let audioUnlocked = false;

    /** ================== LOGGER OVERLAY ================== */
    function createLoggerOverlay() {
        const box = document.createElement('div');
        box.id = 'clipboard-logger';
        box.style.cssText = `
            position: fixed; bottom: 0; left: 0; width: 100%; max-height: 2%;
            overflow-y: auto; font-size: 6px; background: rgba(0,0,0,0.85);
            color: #0f0; padding: 6px; z-index: 2147483646;
            white-space: pre-wrap; font-family: monospace;
        `;
        document.body.appendChild(box);

        const clearBtn = document.createElement('button');
        clearBtn.textContent = '🧹 Clear';
        clearBtn.style.cssText = `
            position: absolute; right: 5px; top: 5px;
            background: #222; color: #fff; border: none;
            padding: 2px 6px; font-size: 12px; cursor: pointer;
        `;
        clearBtn.addEventListener('click', () => { box.textContent = ""; box.appendChild(clearBtn); });
        box.appendChild(clearBtn);

        return box;
    }

    const loggerBox = CONFIG.DEBUG ? createLoggerOverlay() : null;

    function log(msg) {
        if (!CONFIG.DEBUG) return;
        console.log(msg);
        if (loggerBox) {
            const line = document.createElement('div');
            line.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
            loggerBox.appendChild(line);
            loggerBox.scrollTop = loggerBox.scrollHeight;
        }
    }

    /** ================== UTILITIES ================== */
    function stripHTML(text) {
        return text.replace(/]+(>|$)/g, "");
    }
    function cleanText(text) {
        return text.replace(/\n\s*\n/g, "\n").trim();
    }
    function countThaiChars(text) {
        const matches = text.match(/[\u0E00-\u0E7F]/g);
        return matches ? matches.length : 0;
    }
    function countChineseChars(text){
        const matches = text.match(/[\u4e00-\u9fff]/g);
        return matches ? matches.length : 0;
    }
    /* ================== SOUND ================== */
    function setupAudioUnlock() {
        const unlock = () => {
            try {
                if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
                if (audioCtx.state === "suspended") {
                    audioCtx.resume().then(() => { audioUnlocked = true; });
                } else {
                    audioUnlocked = true;
                }
            } catch (e) {
                log(`⚠️ setupAudioUnlock: ${e.message}`, "warn");
            }
            document.removeEventListener("click", unlock, true);
            document.removeEventListener("keydown", unlock, true);
            document.removeEventListener("touchstart", unlock, { capture: true, passive: true });
        };
        document.addEventListener("click", unlock, true);
        document.addEventListener("keydown", unlock, true);
        document.addEventListener("touchstart", unlock, { capture: true, passive: true });
    }

    function beep(freq = CONFIG.BEEP_FREQUENCY) {
        if (!CONFIG.ENABLE_SOUND) return;
        try {
            if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
            if (audioCtx.state === "suspended" && !audioUnlocked) {
                log("🔇 ยังไม่ได้ปลดล็อคเสียง (ต้องแตะจอ/คีย์บอร์ดก่อน)", "warn");
                return;
            }
            const osc = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            osc.type = "sine";
            osc.frequency.value = freq;
            gain.gain.value = CONFIG.BEEP_VOLUME;
            osc.connect(gain);
            gain.connect(audioCtx.destination);
            osc.start();
            osc.stop(audioCtx.currentTime + CONFIG.BEEP_DURATION);
        } catch (e) {
            log(`❌ beep error: ${e.message}`, "error");
        }
    }
    /** ================== MAIN ================== */
    let lastRaw = "";   // ข้อความดิบครั้งก่อน
    let lastClean = ""; // ข้อความที่ clean ครั้งก่อน
    async function checkClipboard() {
        try {
            if (!document.hasFocus()) return;
            const raw = await navigator.clipboard.readText();
            if (!raw || raw === lastRaw) return; // ไม่เปลี่ยน → ไม่ทำงานซ้ำ
            // ✅ ถ้าไม่มีขึ้นบรรทัดใหม่เลย ไม่ต้องทำงาน
//             if (!raw.includes("\n")) {
//                 log("⏩ ข้าม: ไม่มีขึ้นบรรทัดใหม่");
//                 return;
//             }
            lastRaw = raw;
            const rawCount = raw.length;
            const chineseCount = countChineseChars(raw);
            const thaiCount = countThaiChars(raw);

            log(`CN: ${chineseCount}  TH: ${thaiCount}`);

            if (chineseCount > CONFIG.CHINESE_LIMIT) return;// ถ้าจำนวนอักษรจีนเกินไม่ต้องทำงาน

            if (thaiCount > CONFIG.THAI_LIMIT) {
                const clean = cleanText(stripHTML(raw));
                if (clean && clean !== lastClean) {
                    if (CONFIG.KEEP_FORMAT) {
                        GM_setClipboard(clean, "text");
                        log(`Copied with FORMAT kept (${rawCount} chars)`);
                        beep();
                    } else {
                        try {
                            await navigator.clipboard.writeText(clean);
                            log(`Copied as PLAIN text (${rawCount} chars)`);
                            beep();
                        } catch (e) {
                            GM_setClipboard(clean);
                            log(`Copied as PLAIN text (fallback)`);
                            beep();
                        }
                    }
                    lastClean = clean;
                }
            }
        } catch (err) {
            log("⚠️ Clipboard read failed: " + err.message);
        }
    }
    /** ================== LOOP ================== */
    setInterval(checkClipboard, CONFIG.CHECK_INTERVAL);
})();