F95Zone

直接获取被masked的真实链接,无缝翻页

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         F95Zone
// @namespace    -
// @version      1.0.0
// @license      GPL-3.0
// @description  直接获取被masked的真实链接,无缝翻页
// @author       stars-location
// @match        https://f95zone.to/*
// @icon         https://f95zone.to/assets/favicon-32x32.png
// @grant        none
// @run-at       document-end
// ==/UserScript==



(function () {
    'use strict';

    document.addEventListener('click', function (e) {
        const link = e.target.closest('a');
        if (!link || !link.href) return;
       
        try {
            const url = new URL(link.href, window.location.origin);

            if (url.hostname !== 'f95zone.to' || !url.pathname.startsWith('/masked/')) {
                return;
            }
        } catch (err) {
            
            return;
        }

        e.preventDefault();
        e.stopImmediatePropagation();

        const maskedUrl = new URL(link.href, window.location.origin).href;

        fetch(maskedUrl, {
            method: 'POST',
            credentials: 'include',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: 'xhr=1&download=1'
        })
        .then(r => r.json())
        .then(data => {
             if (data.status === 'ok') {
                 window.open(data.msg, '_blank');
             } else {
                 window.open(maskedUrl, '_blank');
             }
        })
    }, true); 
})();



(function () {
    'use strict';

    if (!document.querySelector('.structItem--thread')) return;

    let isLoading = false;
    let hasMore = !!document.querySelector('a.pageNav-jump--next');
    let preloadedDoc = null;

    function preloadNextPage(){
        if (isLoading || !hasMore || preloadedDoc) return;
        isLoading = true;
        const nextLink = document.querySelector('a.pageNav-jump--next');
        if (!nextLink) {
            hasMore = false;
            return;
        }
        const nextPageUrl = nextLink.href;
        fetch(nextPageUrl, { credentials: 'include' })
            .then(res => {
                if (!res.ok) throw new Error('HTTP error'); 
                return res.text();
            })
            .then(html => {
                const doc = new DOMParser().parseFromString(html, 'text/html');
                const messages = doc.querySelector('.block-body')?.querySelectorAll('.message');
                if (messages && messages.length > 0) {
                    preloadedDoc = doc;
                } else {
                    throw 0;
                }
            })
            .catch(() => {})
            .finally(() => {
                isLoading = false;
            });
    }

    function loadNextPage() {
        if (!preloadedDoc) return;
        const newThreads = preloadedDoc.querySelector('.block-body').querySelectorAll('.message');
        const container = document.querySelector('.block-body');
        const nextPageUrl = document.querySelector('a.pageNav-jump--next').href;
        if (container && newThreads.length > 0) {
                newThreads.forEach(thread => container.appendChild(thread));
            }
            
        const newNext = preloadedDoc.querySelector('a.pageNav-jump--next');
        const currentNext = document.querySelector('a.pageNav-jump--next');
        if (newNext && currentNext) currentNext.href = newNext.href; 
        else {
            currentNext.remove(); 
            hasMore = false;
        }
        
        history.replaceState(null, '', nextPageUrl);


        updatePageNum();

        preloadedDoc = null;
    }

    function updatePageNum(){
        const oldPageNavAll = document.querySelectorAll('.pageNav-main');
        const oldPageNav = oldPageNavAll[0];
        const newPageNav = preloadedDoc.querySelector('.pageNav-main');
        const oldPageNum = oldPageNav.querySelector('.pageNav-page--current a').textContent.split('–')[0]; 
        const newPageNum = newPageNav.querySelector('.pageNav-page--current a').textContent;
        const pagesAfterCurrent1 = [];
        const pagesAfterCurrent2 = [];
        let foundCurrent = false;
        for (const li of oldPageNav.querySelectorAll('.pageNav-page')) {
            if (li.classList.contains('pageNav-page--current')) foundCurrent = true;
            if (foundCurrent) pagesAfterCurrent1.push(li);
        }
        pagesAfterCurrent1.forEach(el => el.remove());
        foundCurrent = false;
        for (const li of newPageNav.querySelectorAll('.pageNav-page')) {
            if (li.classList.contains('pageNav-page--current')) {
                foundCurrent = true;
                li.querySelector('a').textContent = oldPageNum + "–" + newPageNum;
            }
            if (foundCurrent) pagesAfterCurrent2.push(li);
        }
        if (pagesAfterCurrent2.length > 0) {
            pagesAfterCurrent2.forEach(nav => oldPageNav.appendChild(nav));
        }
        oldPageNavAll[1].innerHTML = oldPageNavAll[0].innerHTML;
    }


    window.addEventListener('scroll', () => {
        preloadNextPage();
    });
    
    const observer = new IntersectionObserver((entries) => {
        for (const entry of entries) {
            if (entry.isIntersecting) {
                if (preloadedDoc) loadNextPage();
                else preloadNextPage();
            }
        }
    }, { threshold: 0.1 });

    observer.observe(document.querySelectorAll('.pageNav-main')[1]);

})();