Old Reddit AutoTools

Consolidated: Auto-Scroll, Auto-Collapse, Unblur, Over18 Continue, Thumbnail Auto-Expand/Collapse, Moderator Comment Collapse, Infinite Scroll with Page Numbers + Image Embedder

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         Old Reddit AutoTools
// @namespace    http://tampermonkey.net/
// @version      1.3.6
// @description  Consolidated: Auto-Scroll, Auto-Collapse, Unblur, Over18 Continue, Thumbnail Auto-Expand/Collapse, Moderator Comment Collapse, Infinite Scroll with Page Numbers + Image Embedder
// @author       Crates
// @license      MIT
// @match        https://old.reddit.com/*
// @match        https://www.reddit.com/*
// @match        http://old.reddit.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==
(function() {
    'use strict';

    // Track state for infinite scroll
    let isLoading = false;
    let currentPage = 1;
    let postCounter = 0;
    let prefetchedPage = null;
    let prefetchedDoc = null;

    // ========================================
    // UTILITY: Throttle function
    // ========================================
    function throttle(func, limit) {
        let inThrottle;
        return function(...args) {
            if (!inThrottle) {
                func.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }

    // ========================================
    // 1. OVER18 AUTO-CONTINUE
    // ========================================
    function clickContinue() {
        // Method 1: By name attribute (original)
        const buttonsByName = document.getElementsByName('over18');
        for (let button of buttonsByName) {
            if (button.value === "yes") {
                button.click();
                return true;
            }
        }

        // Method 2: Direct button selector with value
        const continueBtn = document.querySelector('button[name="over18"][value="yes"]');
        if (continueBtn) {
            continueBtn.click();
            return true;
        }

        // Method 3: By class (for new Reddit style)
        const primaryBtn = document.querySelector('.c-btn-primary[name="over18"]');
        if (primaryBtn) {
            primaryBtn.click();
            return true;
        }

        // Method 4: Input element (old style)
        const inputBtn = document.querySelector('input[name="over18"][value="yes"]');
        if (inputBtn) {
            inputBtn.click();
            return true;
        }

        // Method 5: Any button/input with "continue" text on over18 pages
        if (window.location.href.includes('over18')) {
            const allButtons = document.querySelectorAll('button[type="submit"], input[type="submit"]');
            for (let btn of allButtons) {
                const text = (btn.textContent || btn.value || '').toLowerCase();
                if (text.includes('continue') || text.includes('yes')) {
                    btn.click();
                    return true;
                }
            }
        }

        return false;
    }

    // ========================================
    // 2. AUTO-COLLAPSE MODERATOR COMMENTS
    // ========================================
    function collapseModeratorComments() {
        document.querySelectorAll('.thing.comment.stickied:not(.collapsed):not([data-auto-collapsed]), .thing.comment:has(.tagline .moderator):not(.collapsed):not([data-auto-collapsed]), .thing.comment:has(.tagline .admin):not(.collapsed):not([data-auto-collapsed])').forEach(comment => {
            const expandBtn = comment.querySelector(':scope > .entry .expand');
            if (expandBtn) {
                comment.setAttribute('data-auto-collapsed', 'true');
                expandBtn.click();
            }
        });
    }

    // ========================================
    // 3. AUTO-EXPAND POST ON COMMENT PAGES
    // ========================================
    function autoExpandPost() {
        if (!document.querySelector('.commentarea')) return;
        const expando = document.querySelector('.thing.link .expando-button.collapsed');
        if (expando) expando.click();
    }

    // ========================================
    // 4. CONSTRAIN OVERSIZED EMBEDS (portrait videos, etc.)
    // ========================================
    function constrainEmbeds() {
        document.querySelectorAll('.expando iframe:not([data-resized])').forEach(iframe => {
            const w = parseInt(iframe.getAttribute('width'));
            const h = parseInt(iframe.getAttribute('height'));
            if (!w || !h) return;

            iframe.setAttribute('data-resized', 'true');

            const maxH = window.innerHeight * 0.65;
            if (h > maxH) {
                const scale = maxH / h;
                iframe.setAttribute('width', Math.round(w * scale));
                iframe.setAttribute('height', Math.round(maxH));
            }
        });
    }

    // ========================================
    // 4.1. NEW: EMBED PLACEHOLDER IMAGES (<image>)
    // ========================================
    function embedPlaceholderImages() {
        const links = document.querySelectorAll('a');
        links.forEach(link => {
            if ((link.textContent.trim() === '<image>' || link.innerText.trim() === '<image>') && !link.dataset.processed) {
                link.dataset.processed = "true";
                const imageUrl = link.href;
                const img = document.createElement('img');
                img.src = imageUrl;

                // Reasonable Size Styling
                img.style.maxWidth = '600px';
                img.style.maxHeight = '500px';
                img.style.width = 'auto';
                img.style.height = 'auto';
                img.style.display = 'block';
                img.style.marginTop = '8px';
                img.style.marginBottom = '8px';
                img.style.borderRadius = '3px';
                img.style.border = '1px solid #ccc';
                img.style.cursor = 'zoom-in';

                // Click to toggle full size
                img.onclick = (e) => {
                    e.preventDefault();
                    if (img.style.maxWidth === '600px') {
                        img.style.maxWidth = '100%';
                        img.style.maxHeight = 'none';
                        img.style.cursor = 'zoom-out';
                    } else {
                        img.style.maxWidth = '600px';
                        img.style.maxHeight = '500px';
                        img.style.cursor = 'zoom-in';
                    }
                };

                link.textContent = '';
                link.appendChild(img);
            }
        });
    }

    // ========================================
    // 5. NUMBER POSTS AND ADD PAGE BREAKS
    // ========================================
    function numberPosts() {
        const posts = document.querySelectorAll('.thing.link:not([data-numbered])');
        if (posts.length === 0) return;

        posts.forEach(post => {
            postCounter++;
            post.setAttribute('data-numbered', 'true');
            post.setAttribute('data-post-number', postCounter);

            const rank = post.querySelector('.rank');
            if (rank) {
                rank.textContent = postCounter;
            }
        });
    }

    // ========================================
    // 6. ADD PAGE SEPARATOR
    // ========================================
    function addPageSeparator(pageNum) {
        const siteTable = document.querySelector('.sitetable.linklisting');
        if (!siteTable) return;

        const separator = document.createElement('div');
        separator.className = 'page-separator';
        separator.setAttribute('data-page', pageNum);
        separator.innerHTML = `
            <div class="page-separator-line"></div>
            <div class="page-separator-label">Page ${pageNum}</div>
            <div class="page-separator-line"></div>
        `;
        siteTable.appendChild(separator);
    }

    // ========================================
    // 7. INFINITE SCROLL (with prefetching)
    // ========================================
    function prefetchNextPage() {
        const nextButton = document.querySelector('.next-button a');
        if (!nextButton || prefetchedDoc) return;

        const url = nextButton.href;
        if (prefetchedPage === url) return;

        prefetchedPage = url;
        fetch(url)
            .then(response => response.text())
            .then(html => {
                const parser = new DOMParser();
                prefetchedDoc = parser.parseFromString(html, 'text/html');
            })
            .catch(() => {
                prefetchedPage = null;
            });
    }

    function loadNextPage() {
        if (isLoading) return;

        const nextButton = document.querySelector('.next-button a');
        if (!nextButton) return;

        isLoading = true;

        const siteTable = document.querySelector('.sitetable.linklisting');
        if (!siteTable) {
            isLoading = false;
            return;
        }

        function appendPosts(doc) {
            currentPage++;
            addPageSeparator(currentPage);

            const newPosts = doc.querySelectorAll('.thing.link');
            newPosts.forEach(post => {
                const clonedPost = post.cloneNode(true);
                clonedPost.removeAttribute('data-numbered');
                siteTable.appendChild(clonedPost);
            });

            const newNextButton = doc.querySelector('.next-button a');
            if (newNextButton) {
                nextButton.href = newNextButton.href;
                prefetchedDoc = null;
                prefetchedPage = null;
                prefetchNextPage();
            } else {
                const navButtons = document.querySelector('.nav-buttons');
                if (navButtons) {
                    navButtons.innerHTML = '<span style="color: #888; padding: 10px;">No more posts</span>';
                }
            }

            numberPosts();
            embedPlaceholderImages(); // Ensure images embed on new pages
            isLoading = false;
        }

        if (prefetchedDoc && prefetchedPage === nextButton.href) {
            appendPosts(prefetchedDoc);
            prefetchedDoc = null;
            prefetchedPage = null;
            return;
        }

        fetch(nextButton.href)
            .then(response => response.text())
            .then(html => {
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                appendPosts(doc);
            })
            .catch(err => {
                console.error('Infinite scroll error:', err);
                isLoading = false;
            });
    }

    function setupInfiniteScroll() {
        if (document.querySelector('.commentarea')) return;

        prefetchNextPage();

        const handleScroll = throttle(() => {
            const scrollPosition = window.innerHeight + window.scrollY;
            const pageHeight = document.documentElement.scrollHeight;

            if (scrollPosition >= pageHeight - 1500) {
                prefetchNextPage();
            }

            if (scrollPosition >= pageHeight - 800) {
                loadNextPage();
            }
        }, 150);

        window.addEventListener('scroll', handleScroll);

        numberPosts();
    }

    // ========================================
    // 8. CLICK-BASED LOGIC
    // ========================================
    let internalClick = false;

    document.addEventListener('click', function(e) {
        const thumbnail = e.target.closest('a.thumbnail');
        if (thumbnail) {
            e.preventDefault();
            const thing = thumbnail.closest('.thing');
            if (thing) {
                const expandoButton = thing.querySelector('.expando-button');
                if (expandoButton) {
                    internalClick = true;
                    expandoButton.click();
                    internalClick = false;
                }
            }
            return;
        }

        const expandoButton = e.target.closest('.expando-button');
        if (expandoButton && expandoButton.classList.contains('collapsed')) {
            if (e.isTrusted || internalClick) {
                document.querySelectorAll('.expando-button.expanded').forEach(btn => {
                    if (btn !== expandoButton) btn.click();
                });

                const thing = expandoButton.closest('.thing');
                if (thing) {
                    setTimeout(() => {
                        thing.scrollIntoView({ behavior: 'smooth', block: 'start' });
                    }, 50);
                }
            }

            setTimeout(() => {
                const nsfwBtn = document.querySelector('button.expando-gate__show-once');
                if (nsfwBtn) nsfwBtn.click();
            }, 100);
        }
    }, true);

    // ========================================
    // 9. MUTATION OBSERVER (Optimized)
    // ========================================
    let observerTimeout = null;

    const observer = new MutationObserver((mutations) => {
        clickContinue();
        const nsfwBtn = document.querySelector('button.expando-gate__show-once');
        if (nsfwBtn) nsfwBtn.click();

        if (observerTimeout) return;

        observerTimeout = setTimeout(() => {
            collapseModeratorComments();
            constrainEmbeds();
            embedPlaceholderImages(); // Catch dynamic image links
            numberPosts();
            observerTimeout = null;
        }, 100);
    });

    // ========================================
    // 10. INITIALIZATION
    // ========================================
    function init() {
        observer.observe(document.documentElement, { childList: true, subtree: true });

        clickContinue();
        setTimeout(clickContinue, 100);
        setTimeout(clickContinue, 300);
        setTimeout(clickContinue, 500);
        setTimeout(clickContinue, 1000);

        collapseModeratorComments();
        autoExpandPost();
        constrainEmbeds();
        embedPlaceholderImages();
        setupInfiniteScroll();

        const style = document.createElement('style');
        style.textContent = `
            .page-separator {
                clear: both;
                width: 100%;
                display: flex;
                align-items: center;
                gap: 14px;
                margin: 20px 0;
                padding: 0 10px;
            }
            .page-separator-line {
                flex: 1;
                height: 1px;
                background: linear-gradient(90deg, transparent, #c0d0e0 15%, #c0d0e0 85%, transparent);
            }
            .page-separator-label {
                font-size: 11px;
                font-weight: 600;
                letter-spacing: 1.5px;
                text-transform: uppercase;
                color: #8aa8c7;
                white-space: nowrap;
            }
            .thing.link {
                border-bottom: 1px solid #e5e5e5 !important;
                padding-bottom: 10px !important;
                margin-bottom: 10px !important;
            }
            .infinite-scroll-loading {
                clear: both;
                width: 100%;
            }
            .rank {
                min-width: 30px !important;
            }
        `;
        document.head.appendChild(style);
    }

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

    window.addEventListener('load', () => {
        clickContinue();
        setTimeout(clickContinue, 500);
    });
})();