Reader view

Reader Mode + Highlight with resilient floating button for tricky sites

18.05.2026 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==UserScript==
// @name         Reader view
// @namespace    http://tampermonkey.net/
// @version      16.10.2025
// @description  Reader Mode + Highlight with resilient floating button for tricky sites
// @author       Copilot
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    let readerOpened = false; // flag to prevent reinjection after Reader Mode

    // ✅ Menu command added
    GM_registerMenuCommand("Open Reader Mode", () => {
        const btn = document.getElementById('tm-reader-btn');
        if (btn) {
            btn.click();
        } else {
            alert("Reader button not available yet.");
        }
    });

    function injectButton() {
        if (readerOpened) return; // stop reinjecting once Reader Mode is active
        if (document.getElementById('tm-reader-box')) return;

        const readerBox = document.createElement('div');
        readerBox.id = 'tm-reader-box';
        const readerBtn = document.createElement('button');
        readerBtn.id = 'tm-reader-btn';
        readerBtn.textContent = 'Reader';
        readerBox.appendChild(readerBtn);

        // Strong CSS
        const style = document.createElement('style');
        style.textContent = `
            #tm-reader-box {
                position: fixed !important;
                bottom: 10px !important;
                right: 60px !important;
                padding: 2px 6px !important;
                background: transparent !important;
                border: 1px solid transparent !important;
                border-radius: 6px !important;
                z-index: 2147483647 !important;
            }
            #tm-reader-btn {
                border: none !important;
                background: transparent !important;
                color: #696969 !important;
                font-size: 12px !important;
                cursor: pointer !important;
                font-family: system-ui, sans-serif !important;

                padding: 0 !important;
                margin: 0 !important;
            }
            #tm-reader-btn:hover { text-decoration: underline !important; }
        `;
        document.head.appendChild(style);

        // Append to both html and body
        if (document.body) document.body.appendChild(readerBox);
        document.documentElement.appendChild(readerBox);

        // Reader Mode logic
        readerBtn.addEventListener('click', async function() {
            const loadScript = url => new Promise((resolve, reject) => {
                const script = document.createElement('script');
                script.src = url;
                script.onload = resolve;
                script.onerror = reject;
                document.head.appendChild(script);
            });

            try {
                if (!window.Readability) {
                    await loadScript('https://cdn.jsdelivr.net/npm/@mozilla/[email protected]/Readability.js');
                }
                if (!window.DOMPurify) {
                    await loadScript('https://cdn.jsdelivr.net/npm/[email protected]/dist/purify.min.js');
                }

                const clone = document.cloneNode(true);
                const article = new Readability(clone).parse();
                if (!article) {
                    alert('Reader Mode: No article found on this page.');
                    return;
                }

                // Remove the floating Reader button completely
                const readerBox = document.getElementById('tm-reader-box');
                if (readerBox) readerBox.remove();
                readerOpened = true; // prevent reinjection

                const css = `
                    html, body { margin:0; padding:0; background:#fff; }
                    body {
                        font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif !important;
                        max-width: 48rem;
                        margin: 0 auto;
                        padding: 2rem;
                        color: #111;
                        line-height: 1.6;
                    }
                    article *, article {
                        font-size: 28px !important;
                        font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif !important;
                    }
                    p, div, span, li { margin-bottom:1.5rem; word-break:normal; overflow-wrap:break-word; }
                    h1,h2,h3,h4,h5,h6 { line-height:1.3; margin:1.5rem 0 0.5rem; font-weight:700; }
                    a { color:#0b57d0; text-decoration:none; cursor:pointer; }
                    a:hover { text-decoration:underline; }
                    img, video { max-width:100%; height:auto; border-radius:8px; display:block; margin:2rem auto; }
                    pre, code { font-family: ui-monospace, monospace !important; font-size:22px !important; background:#f5f5f5; padding:0.2em 0.4em; border-radius:3px; }
                    @media (prefers-color-scheme: dark) {
                        html, body { background:#111; }
                        body { color:#eee; }
                        pre, code { background:#222; }
                        a { color:#4a90e2; }
                    }
                `;

                const html = `
                    <!DOCTYPE html>
                    <html>
                    <head>
                        <meta charset="utf-8">
                        <meta name="viewport" content="width=device-width, initial-scale=1.0">
                        <title>${article.title || 'Reader Mode'}</title>
                        <style>${css}</style>
                    </head>
                    <body>
                        <article>
                            <h1>${article.title || ''}</h1>
                            <div>${window.DOMPurify ? DOMPurify.sanitize(article.content) : article.content}</div>
                        </article>
                    </body>
                    </html>
                `;

                document.open();
                document.write(html);
                document.close();

                // Highlight button
                const btn = document.createElement('button');
                btn.innerText = '🖍️';
                btn.id = 'tm-highlight-btn';
                btn.style.cssText = `
                    position: fixed;
                    bottom: 20px;
                    right: 20px;
                    z-index: 10000;
                    padding: 10px;
                    border-radius: 50%;
                    background-color: #ffeb3b;
                    border: 2px solid #000;
                    font-size: 20px;
                    display: none;
                `;
                document.body.appendChild(btn);

                document.addEventListener('selectionchange', () => {
                    const selection = window.getSelection();
                    btn.style.display = (selection.toString().length > 0) ? 'block' : 'none';
                });

                btn.addEventListener('click', () => {
                    const selection = window.getSelection();
                    if (!selection.rangeCount) return;
                    const range = selection.getRangeAt(0);
                    const mark = document.createElement('mark');
                    mark.style.backgroundColor = 'yellow';
                    mark.style.color = 'black';
                    try {
                        range.surroundContents(mark);
                        selection.removeAllRanges();
                        btn.style.display = 'none';
                    } catch (e) {
                        alert("Can't highlight across multiple complex elements. Try a smaller selection!");
                    }
                });
            } catch (err) {
                alert('Reader Mode failed: ' + err.message);
            }
        });
    }

    // Inject after load
    window.addEventListener('load', injectButton);

    // Reinjection checks
    const observer = new MutationObserver(() => injectButton());
    observer.observe(document.documentElement, { childList: true, subtree: true });
    setInterval(injectButton, 2000);
})();