Rule34 Custom Blocker (Tags & Users)

Hides posts with specified tags, artists, or users and intelligently skips them in the post view based on your navigation direction.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Rule34 Custom Blocker (Tags & Users)
// @name:tr      Rule34 Özel Engelleyici (Etiketler ve Kullanıcılar)
// @namespace    https://greasyfork.org/en/users/1500762-kerimdemirkaynak
// @version      3.2
// @description  Hides posts with specified tags, artists, or users and intelligently skips them in the post view based on your navigation direction.
// @description:tr Belirlenen etiketlere, çizerlere veya yükleyicilere sahip gönderileri gizler ve tekli gönderi görünümünde gezinme yönünüze göre otomatik olarak atlar.
// @author       Kerim Demirkaynak
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=256&domain_url=https%3A%2F%2Frule34.xxx%2F
// @match        https://rule34.xxx/index.php*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    // Engellenecek etiketleri, çizerleri veya kullanıcıları bu listeye ekleyebilirsiniz.
    // İstenmeyen çizerleri etiket olarak (örn: "trash_artist") ekleyebilirsiniz.
    // Kullanıcıları (yükleyicileri) engellemek için başına "user:" ekleyin (örn: "user:GokuYellow")
    const blockList = [
        'futanari',
        'futa_on_male',
        'futa_on_futa',
        'dickgirl',
        'shemale',
        'gutanari',
        'user:furreal99',
        'user:GokuYellow'
        // ve diğer istemediğiniz etiket/kullanıcılar...
    ];

    const blockedTags = [];
    const blockedUsers = [];

    // Listeyi etiketler ve kullanıcılar olarak ikiye ayırıyoruz
    blockList.forEach(item => {
        const lowerItem = item.toLowerCase().trim();
        if (lowerItem.startsWith('user:')) {
            blockedUsers.push(lowerItem.replace('user:', '').trim());
        } else {
            blockedTags.push(lowerItem);
        }
    });

    const urlParams = new URLSearchParams(window.location.search);
    const pageType = urlParams.get('s');

    // --- Izgara/Liste Görünümü İçin (Ana Sayfa) ---
    if (pageType === 'list' || !pageType) {
        const hideThumbnails = () => {
            document.querySelectorAll('span.thumb').forEach(thumb => {
                if (thumb.style.display === 'none') return;
                const img = thumb.querySelector('img.preview');
                
                // Not: Liste görünümünde sadece etiketleri kontrol edebiliriz
                // Yükleyici (uploader) bilgisi Rule34 liste DOM yapısında varsayılan olarak bulunmaz.
                if (img && img.title && blockedTags.some(tag => img.title.toLowerCase().includes(tag))) {
                    thumb.style.display = 'none';
                }
            });
        };

        const listObserver = new MutationObserver(hideThumbnails);
        const imageList = document.getElementById('post-list');
        if (imageList) {
            listObserver.observe(imageList, { childList: true, subtree: true });
        }
        hideThumbnails();
    }

    // --- Tekli Gönderi/Görüntüleme Sayfası İçin (Akıllı Atlatma) ---
    if (pageType === 'view') {
        let lastKnownDirection = 'next'; // Varsayılan yön

        const setupDirectionListeners = () => {
            const nextButton = document.getElementById('next_search_link');
            const prevButton = document.getElementById('prev_search_link');
            if (nextButton) nextButton.addEventListener('mousedown', () => { lastKnownDirection = 'next'; }, true);
            if (prevButton) prevButton.addEventListener('mousedown', () => { lastKnownDirection = 'prev'; }, true);
        };

        const checkAndSkip = () => {
            const tagList = document.getElementById('tag-sidebar');
            const image = document.getElementById('image');
            if (!tagList || !image) return;

            // Kontrol etmeden önce resmi görünür yap (bir önceki gizlenmiş olabilir)
            image.style.visibility = 'visible';

            // 1. Etiketleri / Çizerleri al
            const currentTags = Array.from(tagList.querySelectorAll('li a')).map(a => a.innerText.toLowerCase().replace(/ /g, '_'));
            
            // 2. Yükleyiciyi (Uploader / User) İstatistik sekmesinden al
            const uploaderNode = document.querySelector('#stats a[href*="uname="]');
            const currentUploader = uploaderNode ? uploaderNode.innerText.trim().toLowerCase() : '';

            // Yasaklı kontrolü
            const isForbiddenTag = currentTags.some(currentTag => blockedTags.some(blocked => currentTag.includes(blocked)));
            const isForbiddenUser = blockedUsers.includes(currentUploader);

            if (isForbiddenTag || isForbiddenUser) {
                // 1. Resmi anında gizle
                image.style.visibility = 'hidden';
                console.log(`Engellenen içerik algılandı. Yön: ${lastKnownDirection}. Atlanıyor...`);

                // 2. Doğru yöndeki butona tıkla
                const buttonToClick = (lastKnownDirection === 'next')
                    ? document.getElementById('next_search_link')
                    : document.getElementById('prev_search_link');

                if (buttonToClick && buttonToClick.href && !buttonToClick.href.endsWith('#')) {
                    buttonToClick.click();
                }
            }
        };

        // Gözlemci: Sayfa içeriği (etiketler, resim) değiştiğinde tetiklenir
        const viewObserver = new MutationObserver(() => {
            checkAndSkip();
            // Butonlar da yeniden yüklenebileceği için dinleyicileri tekrar kur
            setupDirectionListeners();
        });

        const targetNode = document.getElementById('post-view');
        if (targetNode) {
            viewObserver.observe(targetNode, { childList: true, subtree: true });
        }

        // Sayfa ilk yüklendiğinde işlemleri başlat
        setupDirectionListeners();
        checkAndSkip(); // setTimeout olmadan daha hızlı çalışır
    }
})();