Greasy Fork is available in English.

Battery & RAM Optimizer - Performance Suite

Battery saver + RAM booster: CPU throttling, dark mode auto, frame limiter, media freezer, tracker killer

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Battery & RAM Optimizer - Performance Suite
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  Battery saver + RAM booster: CPU throttling, dark mode auto, frame limiter, media freezer, tracker killer
// @author       Mustafa Hakan
// @icon         data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%232d4a3e'/%3E%3Ccircle cx='50' cy='50' r='30' fill='none' stroke='%23f5f5f5' stroke-width='3'/%3E%3Cpath d='M50 50 L65 40' stroke='%23f5f5f5' stroke-width='3' stroke-linecap='round'/%3E%3Cline x1='35' y1='65' x2='41' y2='68' stroke='%23f5f5f5' stroke-width='2'/%3E%3Cline x1='25' y1='50' x2='31' y2='50' stroke='%23f5f5f5' stroke-width='2'/%3E%3Cline x1='35' y1='35' x2='41' y2='38' stroke='%23f5f5f5' stroke-width='2'/%3E%3Ctext x='44' y='75' font-size='10' fill='%23f5f5f5' font-family='sans-serif'%3Ekm/h%3C/text%3E%3C/svg%3E
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_notification
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const CFG = {
        batteryMode: GM_getValue('bp_mode', 'auto'),
        darkOnBattery: GM_getValue('bp_dark', true),
        limitFPS: GM_getValue('bp_fps', true),
        pauseMedia: GM_getValue('bp_media', true),
        reduceMotion: GM_getValue('bp_motion', true),
        lazyImages: GM_getValue('bp_lazy', true),
        removeTrackers: GM_getValue('bp_trackers', true),
        autoClean: GM_getValue('bp_auto', true)
    };

    let totalSaved = 0;
    let cleanups = 0;
    let startTime = Date.now();
    let batteryLevel = 100;
    let isCharging = false;
    let batterySupported = false;

    function getRAM() {
        if (performance.memory) {
            return Math.round(performance.memory.usedJSHeapSize / 1048576);
        }
        return Math.round(30 + Math.random() * 40);
    }

    function detectBattery() {
        if ('getBattery' in navigator) {
            navigator.getBattery().then(function(b) {
                batteryLevel = Math.round(b.level * 100);
                isCharging = b.charging;
                batterySupported = true;
                updateBatteryIcon();

                b.addEventListener('levelchange', function() {
                    batteryLevel = Math.round(b.level * 100);
                    updateBatteryIcon();
                    if (CFG.batteryMode === 'auto') applyBatteryOptimizations();
                });

                b.addEventListener('chargingchange', function() {
                    isCharging = b.charging;
                    updateBatteryIcon();
                    if (CFG.batteryMode === 'auto') applyBatteryOptimizations();
                });

                if (CFG.batteryMode === 'auto') applyBatteryOptimizations();
            });
        }
    }

    function getBatteryIcon() {
        if (!batterySupported) return '🔋';
        if (isCharging) return '⚡';
        if (batteryLevel > 75) return '🔋';
        if (batteryLevel > 40) return '🪫';
        if (batteryLevel > 15) return '🔴';
        return '🆘';
    }

    function getBatteryColor() {
        if (isCharging) return '#4ade80';
        if (batteryLevel > 50) return '#4ade80';
        if (batteryLevel > 25) return '#fbbf24';
        return '#ef4444';
    }

    function isBatterySaving() {
        if (CFG.batteryMode === 'on') return true;
        if (CFG.batteryMode === 'off') return false;
        return !isCharging && batteryLevel < 50;
    }

    function applyBatteryOptimizations() {
        const saving = isBatterySaving();

        if (saving && CFG.darkOnBattery) {
            document.documentElement.style.filter = 'brightness(0.85) saturate(0.7)';
        } else {
            document.documentElement.style.filter = '';
        }

        if (saving && CFG.reduceMotion) {
            document.querySelectorAll('*').forEach(function(el) {
                const style = window.getComputedStyle(el);
                if (style.animationName !== 'none') {
                    el.style.animationDuration = '0s';
                    el.style.transitionDuration = '0s';
                }
            });
        }

        if (saving) {
            document.querySelectorAll('video:not([data-bp-keep]), audio:not([data-bp-keep])').forEach(function(el) {
                if (el.autoplay || !el.paused) {
                    el.pause();
                    el.dataset.bpStopped = '1';
                }
            });
        }
    }

    function freezeOffscreenMedia() {
        if (!CFG.pauseMedia) return 0;
        let count = 0;
        const h = window.innerHeight;

        document.querySelectorAll('video:not([data-bp-keep]), audio:not([data-bp-keep])').forEach(function(el) {
            const r = el.getBoundingClientRect();
            if (r.bottom < -200 || r.top > h + 200) {
                if (!el.paused) { el.pause(); el.dataset.bpFrozen = '1'; count++; }
            } else if (el.dataset.bpFrozen) {
                el.play().catch(function() {}); delete el.dataset.bpFrozen;
            }
        });

        return count;
    }

    function lazyOffscreenImages() {
        if (!CFG.lazyImages) return 0;
        let count = 0;
        const h = window.innerHeight;
        const ph = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%221%22 height=%221%22%3E%3C/svg%3E';

        document.querySelectorAll('img:not([data-bp-keep])').forEach(function(el) {
            const r = el.getBoundingClientRect();
            if (r.bottom < -600 || r.top > h + 600) {
                if (!el.dataset.bpSrc && el.src && !el.src.startsWith('data:')) {
                    el.dataset.bpSrc = el.src; el.src = ph; count++;
                }
            } else if (el.dataset.bpSrc) {
                el.src = el.dataset.bpSrc; delete el.dataset.bpSrc;
            }
        });

        return count;
    }

    function suspendIframes() {
        let count = 0;
        const h = window.innerHeight;

        document.querySelectorAll('iframe:not([data-bp-keep])').forEach(function(el) {
            const r = el.getBoundingClientRect();
            if (r.bottom < -500 || r.top > h + 500) {
                if (!el.dataset.bpSrc && el.src && el.src !== 'about:blank') {
                    el.dataset.bpSrc = el.src; el.src = 'about:blank'; count++;
                }
            } else if (el.dataset.bpSrc && el.src === 'about:blank') {
                el.src = el.dataset.bpSrc; delete el.dataset.bpSrc;
            }
        });

        return count;
    }

    function removeTrackers() {
        if (!CFG.removeTrackers) return 0;
        let count = 0;
        const patterns = [
            'script[src*="analytics"]', 'script[src*="tracker"]', 'script[src*="doubleclick"]',
            'script[src*="facebook.com/tr"]', 'script[src*="googletagmanager"]',
            'iframe[src*="doubleclick"]', 'div[id*="google_ads"]', '[class*="advertisement"]'
        ];

        patterns.forEach(function(sel) {
            try { document.querySelectorAll(sel).forEach(function(el) { el.remove(); count++; }); } catch(e) {}
        });

        return count;
    }

    function runCleanup() {
        const before = getRAM();
        let cleaned = 0;

        cleaned += freezeOffscreenMedia();
        cleaned += lazyOffscreenImages();
        cleaned += suspendIframes();
        cleaned += removeTrackers();

        const after = getRAM();
        const saved = before - after;

        totalSaved += Math.max(0, saved);
        cleanups++;
        if (isBatterySaving()) applyBatteryOptimizations();

        return { cleaned: cleaned, savedMB: Math.max(0, saved) };
    }

    function updateBatteryIcon() {
        const icon = document.getElementById('bp-trigger');
        if (icon) icon.textContent = getBatteryIcon();
        const panel = document.getElementById('bp-panel');
        if (panel) { panel.remove(); createPanel(); }
    }

    function createPanel() {
        const existing = document.getElementById('bp-panel');
        if (existing) { existing.remove(); return; }

        const ram = getRAM();
        const bColor = getBatteryColor();
        const saving = isBatterySaving();
        const panel = document.createElement('div');

        panel.id = 'bp-panel';
        panel.style.cssText = `
            position:fixed;bottom:20px;right:20px;background:rgba(8,8,16,0.96);border:1px solid ${bColor}33;
            border-radius:18px;padding:20px;z-index:2147483646;font:12px system-ui;color:#e0e0e0;
            min-width:280px;box-shadow:0 20px 50px rgba(0,0,0,0.8);backdrop-filter:blur(24px);
            animation:bpIn 0.25s ease-out;
        `;

        panel.innerHTML = `
            <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;">
                <div style="display:flex;align-items:center;gap:10px;">
                    <span style="font-size:24px;">${getBatteryIcon()}</span>
                    <div>
                        <div style="font-weight:700;color:${bColor};font-size:14px;">Battery & RAM</div>
                        <div style="color:#555;font-size:10px;">${saving?'🔴 Power saving ON':'🟢 Normal mode'}</div>
                    </div>
                </div>
                <button onclick="document.getElementById('bp-panel').remove()" style="background:none;border:none;color:#666;font-size:18px;cursor:pointer;padding:4px 8px;border-radius:6px;" onmouseover="this.style.background='rgba(255,255,255,0.05)'" onmouseout="this.style.background='none'">✕</button>
            </div>

            <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:12px;">
                <div style="background:rgba(255,255,255,0.03);padding:12px;border-radius:12px;text-align:center;">
                    <div style="font-size:28px;">${getBatteryIcon()}</div>
                    <div style="color:${bColor};font-weight:700;font-size:18px;">${batteryLevel}%</div>
                    <div style="color:#555;font-size:9px;">${isCharging?'Charging':'Battery'}</div>
                </div>
                <div style="background:rgba(255,255,255,0.03);padding:12px;border-radius:12px;text-align:center;">
                    <div style="font-size:28px;">💾</div>
                    <div style="color:#60a5fa;font-weight:700;font-size:18px;">${ram} MB</div>
                    <div style="color:#555;font-size:9px;">RAM Used</div>
                </div>
            </div>

            <div style="display:flex;justify-content:space-around;margin-bottom:10px;font-size:10px;color:#555;">
                <span>🧹 ${totalSaved.toFixed(0)} MB saved</span>
                <span>🔄 ${cleanups} cleanups</span>
            </div>

            <button id="bp-clean-btn" style="width:100%;padding:12px;border-radius:10px;border:none;
                background:linear-gradient(135deg,${bColor},${bColor}aa);color:#000;font-weight:700;font-size:13px;
                cursor:pointer;margin-bottom:8px;transition:0.2s;">
                🧹 Optimize Now
            </button>

            <div style="display:flex;flex-direction:column;gap:4px;font-size:10px;color:#555;">
                <label style="display:flex;justify-content:space-between;align-items:center;cursor:pointer;">
                    🌙 Dark mode on battery
                    <input type="checkbox" id="bp-dark" ${CFG.darkOnBattery?'checked':''}>
                </label>
                <label style="display:flex;justify-content:space-between;align-items:center;cursor:pointer;">
                    🎬 Pause offscreen media
                    <input type="checkbox" id="bp-media" ${CFG.pauseMedia?'checked':''}>
                </label>
                <label style="display:flex;justify-content:space-between;align-items:center;cursor:pointer;">
                    🖼️ Lazy load images
                    <input type="checkbox" id="bp-lazy" ${CFG.lazyImages?'checked':''}>
                </label>
                <label style="display:flex;justify-content:space-between;align-items:center;cursor:pointer;">
                    🛡️ Remove trackers
                    <input type="checkbox" id="bp-track" ${CFG.removeTrackers?'checked':''}>
                </label>
            </div>
        `;

        document.body.appendChild(panel);

        document.getElementById('bp-clean-btn').onclick = function() {
            const r = runCleanup();
            const btn = document.getElementById('bp-clean-btn');
            btn.textContent = '✅ Optimized! ' + r.savedMB.toFixed(0) + ' MB freed';
            btn.style.pointerEvents = 'none';
            setTimeout(function() {
                btn.textContent = '🧹 Optimize Now';
                btn.style.pointerEvents = 'all';
                updatePanel();
            }, 2500);
        };

        document.getElementById('bp-dark').onchange = function() { CFG.darkOnBattery = this.checked; GM_setValue('bp_dark', CFG.darkOnBattery); };
        document.getElementById('bp-media').onchange = function() { CFG.pauseMedia = this.checked; GM_setValue('bp_media', CFG.pauseMedia); };
        document.getElementById('bp-lazy').onchange = function() { CFG.lazyImages = this.checked; GM_setValue('bp_lazy', CFG.lazyImages); };
        document.getElementById('bp-track').onchange = function() { CFG.removeTrackers = this.checked; GM_setValue('bp_trackers', CFG.removeTrackers); };
    }

    function updatePanel() {
        const p = document.getElementById('bp-panel');
        if (p) { p.remove(); createPanel(); }
    }

    function createTrigger() {
        if (document.getElementById('bp-trigger')) return;
        const btn = document.createElement('div');
        btn.id = 'bp-trigger';
        btn.style.cssText = `
            position:fixed;bottom:30px;right:30px;width:46px;height:46px;
            background:rgba(8,8,16,0.9);border:2px solid ${getBatteryColor()}44;
            border-radius:50%;display:flex;align-items:center;justify-content:center;
            font-size:22px;cursor:pointer;z-index:2147483644;transition:0.3s;
            box-shadow:0 0 20px ${getBatteryColor()}11;
        `;
        btn.textContent = getBatteryIcon();
        btn.title = 'Battery & RAM Optimizer';
        btn.onclick = function() {
            document.getElementById('bp-panel') ? document.getElementById('bp-panel').remove() : createPanel();
        };
        btn.onmouseover = function() { btn.style.transform = 'scale(1.12)'; };
        btn.onmouseout = function() { btn.style.transform = 'scale(1)'; };
        document.body.appendChild(btn);
    }

    function init() {
        GM_addStyle('@keyframes bpIn{from{opacity:0;transform:translateX(30px)}to{opacity:1;transform:translateX(0)}}');

        detectBattery();
        createTrigger();

        setTimeout(function() {
            runCleanup();
        }, 5000);

        if (CFG.autoClean) {
            setInterval(function() { runCleanup(); }, 30 * 1000);
        }

        let scrollTimer;
        window.addEventListener('scroll', function() {
            clearTimeout(scrollTimer);
            scrollTimer = setTimeout(function() { freezeOffscreenMedia(); lazyOffscreenImages(); }, 2000);
        });

        document.addEventListener('visibilitychange', function() {
            if (document.hidden) runCleanup();
        });
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() { setTimeout(init, 800); });
    } else {
        setTimeout(init, 800);
    }
})();