RPDL Uploader Enhancements

Provides various enhancements to uploading workflow.

// ==UserScript==
// @name            RPDL Uploader Enhancements
// @namespace       https://github.com/rpdl-net/userscripts/
// @version         1.4-alpha.10
// @description     Provides various enhancements to uploading workflow.
// @author          rpdl-net
// @match           https://dl.rpdl.net/*
// @match           https://jenkins.rpdl.net/*
// @match           https://f95zone.to/threads/*
// @grant           GM_setValue
// @grant           GM_getValue
// @grant           GM_deleteValue
// @grant           window.onurlchange
// @require         https://code.jquery.com/jquery-3.7.1.min.js
// @tag             access-required
// @icon            https://dl.rpdl.net/favicon.ico
// @homepage        https://github.com/rpdl-net/userscripts/tree/main/uploader-enhancements
// @supportURL      https://github.com/rpdl-net/userscripts/issues
// ==/UserScript==

    (function() {
        'use strict';
       
        // Define your Jenkins username here; used for redirect to build-new, and dropdown selectors jobs (transfer, token-update)
        let username = GM_getValue('username');
        if (username === undefined || username === null || username === '') {
            const username = "";
            // Input your username above.
            // const username = "bob";
            GM_setValue('username', username);}

        // Pastes the pulled values to their respective boxes, if found
        function pasteAll() {
            // Selects and fills the dropdown found on Torrent-Transfer with the username defined at the beginning of the script, or the dropdown found on Build-New with the engine value saved in GM_setValue('engine')
            // Paste is set to occur on page load, so dropdown can still be modified if transfering to another uploader, or if engine needs to be modified
            const dropdown = document.querySelector('div.jenkins-select[name="parameter"]');
            if (dropdown) {
                const usernameOption = dropdown.querySelector(`option[value="${username}"]`);
                const engineOption = dropdown.querySelector(`option[value="${GM_getValue('engine')}"]`);
                if (usernameOption) {
                    usernameOption.selected = true;
                } else if (engineOption) {
                    engineOption.selected = true;}}
            // Calls clearAllValues to remove saved/pasted values from storage after half a second
            setTimeout(clearAllValues, 500);
        }

        // Creates torrent page button style, and adds click handlers for left-click, middle-click, or new tab opening
        function createButton(text, url) {
            const button = document.createElement('button');
            button.href = url;
            button.textContent = text;
            button.classList.add("rounded-md", "px-3", "ml-2", "text-md", "text-white");
            // Applies default style
            button.style.backgroundColor = '#44557a'; // bg color 1
            button.style.borderColor = '#4d608a'; // border color 1
            button.style.borderWidth = '0.5px';
            // Applies hover style on mouseover
            button.addEventListener('mouseover', function() {
                button.style.backgroundColor = '#293349'; // bg color 2
                button.style.borderColor = '#293349';}); // border color 2
            // Resets to default style on mouseout
            button.addEventListener('mouseout', function() {
                button.style.backgroundColor = '#44557a'; // bg color 1
                button.style.borderColor = '#4d608a';}); // border color 1
            // Click event handlers
            button.addEventListener('click', (event) => {
                event.preventDefault(); // Prevent the default action (redirecting the current page)
                window.open(url, '_blank');});
            button.addEventListener('auxclick', (event) => {
                if ((event.button === 1 || (event.button === 0 && event.ctrlKey)) && event.target === button) {
                    clickHandler(event);}}
                                   );
            return button;
        }

        // Adds buttons to torrent pages
        function addButtonsOnTorrentPage() {
            const torrentPage = document.querySelector('div .truncate').parentElement;
            const buildNewButton = createButton('Build-new', `https://jenkins.rpdl.net/job/build-${username}-new/build`);
            const deleteButton = createButton('Delete', 'https://jenkins.rpdl.net/job/torrent-delete/build');
            const renameButton = createButton('Rename', 'https://jenkins.rpdl.net/job/torrent-rename/build');
            const transferButton = createButton('Transfer', 'https://jenkins.rpdl.net/job/torrent-transfer/build');

            const buttonContainer = document.createElement('div');
            buttonContainer.classList.add("flex")
            buttonContainer.appendChild(buildNewButton);
            buttonContainer.appendChild(deleteButton);
            buttonContainer.appendChild(renameButton);
            buttonContainer.appendChild(transferButton);

            torrentPage.appendChild(buttonContainer);
        }

        // Creates F95 thread button style
        function createF95Button(text) {
            const button = document.createElement('a');
            button.textContent = text;
            button.classList.add('button--link', 'button');
            button.style.color = '#ffffff';
            button.style.backgroundColor = '#44557a';
            button.style.borderColor = '#4d608a';
            button.style.borderWidth = '0.5px';
            button.addEventListener('mouseover', function() {
                button.style.backgroundColor = '#293349';
                button.style.borderColor = '#293349';});
            button.addEventListener('mouseout', function() {
                button.style.backgroundColor = '#44557a';
                button.style.borderColor = '#4d608a';});
            button.addEventListener('click', (event) => {
                event.preventDefault();
                var buttonText = button.textContent.trim();
                if (buttonText === "Last page") {
                    goToLast();}});
            return button;
        }

        // Adds buttons to F95 threads
        function addF95Button() {
            const buttonGroup = document.querySelector('.buttonGroup');
            // const firstButton = buttonGroup.querySelector('.button--link.button');
            if (buttonGroup) {
                const lastButton = createF95Button('Last page');
                const firstButton = buttonGroup.querySelector('.button--link.button');
                var currentPage = window.location.href;
                if (/slide=\d+$/.test(currentPage)) {
                    return;
                } else {
                    if (firstButton.href !== lastButton.href) {
                        buttonGroup.insertBefore(lastButton, firstButton);
                    }
                }
            }
        }

        // Redirects to the last page of the thread
        function goToLast() {
            var currentPage = window.location.href;
            if (/\/page-\d+$/.test(currentPage)) {
                var newPage = currentPage.replace(/\/page-\d+$/, '/latest');
            } else {
                var newPage = currentPage.replace(/\/$/, '') + '/latest';
            }
            window.location.href = newPage;
        }

        // Function to find the rpdl.net/docs link and create a floating button
    function pasteSniffer() {
        const pageBody = document.querySelector('div.p-body');
        if (!pageBody) {
            console.log('Page body not found!');
            return;
        }

        const linkElements = pageBody.querySelectorAll('a');
        let rpdlLinkFound = false;
        let postLink = null;

        // Search through all the links on the page to find the rpdl.net/docs link
        for (const link of linkElements) {
            const href = link.getAttribute('href');
            if (href === 'https://rpdl.net/docs/') {
                console.log('Found the rpdl.net/docs link:', href);
                rpdlLinkFound = true;

                // Look for the post link near this rpdl.net/docs link
                let postContainer = link.closest('.message');
                if (postContainer) {
                    const postLinkElement = postContainer.querySelector('a[href^="/threads"]'); // Look for post link inside this post
                    if (postLinkElement) {
                        postLink = `https://f95zone.to${postLinkElement.getAttribute('href')}`;
                        console.log('Found the associated post link:', postLink);
                    }
                }
                break; // Exit once we find the rpdl.net/docs link and its associated post link
            }
        }

        if (rpdlLinkFound && postLink) {
            // Create a floating button if the rpdl.net/docs and post link are found
            createPasteButton(postLink);
        } else {
            console.log('Did not find the rpdl.net/docs link or associated post link.');
        }
    }

    // Create a floating button and add it to the page
    function createPasteButton(postLink) {
        const button = document.createElement('button');
        button.textContent = 'Open Post Link';
        button.style.position = 'fixed';
        button.style.bottom = '20px';
        button.style.left = '20px';
        button.style.padding = '10px 20px';
        button.style.fontSize = '14px';
        button.style.backgroundColor = '#007BFF';
        button.style.color = '#fff';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.cursor = 'pointer';
        button.style.zIndex = '9999';

        // When the button is clicked, open the post link in the current window
        button.addEventListener('click', () => {
            window.location.href = postLink;
        });

        document.body.appendChild(button);
    }

function hostSniffer() {
    const f95Links = document.querySelectorAll('a[class*="link link--external"]');
    const processedUrls = new Set();
    f95Links.forEach(link => {
        const backgroundImage = getComputedStyle(link).backgroundImage;
        const urlMatch = backgroundImage.match(/url\(['"]?(.*?)['"]?\)/);
        if (urlMatch && urlMatch[1]) {
            const url = urlMatch[1];
            if ((url.includes("anonymfile") || url.includes("catbox") || url.includes("delafil") ||
           url.includes("download.gg") || url.includes("files.dp.ua") || url.includes("filesfm") ||
           url.includes("up2share") || url.includes("drive.google") || url.includes("bowfile") || url.includes("mediafire") ||
           url.includes("gofile") || url.includes("uploadnow") || url.includes("yourfilestore") ||
           url.includes("buzzheavier") || url.includes("pixeldrain")) && !processedUrls.has(url)) {
                processedUrls.add(url);
                // Target the inner span if it exists
                const span = link.querySelector('span');
                if (span) {
                    span.style.color = '#4CBB17'; // Override span's color
                } else {
                    link.style.color = '#4CBB17'; // Fallback for links without spans
                }
            }
        }
    });
};

        function init(){
            // Checks if the current page is a Jenkins job (which is not rebuild screen) or a torrent page
            const isJenkinsJob = window.location.href.startsWith("https://jenkins.rpdl.net/job/") && !window.location.href.includes("rebuild");
            const isTorrentPage = window.location.href.match(/^https:\/\/dl\.rpdl\.net\/torrent\/\d+$/);
            const isF95Page = /^https:\/\/f95zone\.to\/threads\/[^/]+/.test(window.location.href);
            // If on a Jenkins job, it waits for the page to load and calls pasteAll
            if(isJenkinsJob){
                window.addEventListener("load", pasteAll);
            // If on a torrent page, it adds the buttons
            }else if(isTorrentPage){
                waitForKeyElements("div .truncate", addButtonsOnTorrentPage);
            // If on a F95 page, it adds the buttons
            } else if (isF95Page) {
                addF95Button();
                pasteSniffer();
                hostSniffer();
            // If on another page, calls clearAllValues to remove saved/pasted values from storage
            }
        }

        // When changing pages, calls init to check if on Jenkins job or torrent page
        if(!window.onurlchange){
            window.addEventListener("urlchange", init);
        }

        // Calls init to check if on Jenkins job or torrent page
        init();

        // Redirects on post-job pages
        function performRedirect() {
            const currentUrl = window.location.href;
            // Build-new post-job redirects to new Build-new job
            if (currentUrl === `https://jenkins.rpdl.net/job/build-${username}-new/`) {
                setTimeout(() => {window.location.replace(`https://jenkins.rpdl.net/job/build-${username}-new/build`)}, 500);
            // Torrent-Delete post-job redirects to new Torrent-Delete job
    // Note: Torrent-Delete redirect is disabled by default so the post-job screen can act as a visual confirmation of completion. To enable, remove the slashes at the start of the next 2 lines.
    //        } else if (currentUrl === 'https://jenkins.rpdl.net/job/torrent-delete/') {
    //            setTimeout(() => {window.location.replace('https://jenkins.rpdl.net/job/torrent-delete/build')}, 500);
            // Torrent-Rename and Torrent-Transfer post-jobs redirect to dashboard
            } else if (currentUrl === 'https://jenkins.rpdl.net/job/torrent-rename/' || currentUrl === 'https://jenkins.rpdl.net/job/torrent-transfer/') {
                window.location.replace('https://jenkins.rpdl.net/');
            }
        }

        function waitForKeyElements (selectorTxt,actionFunction,bWaitOnce,iframeSelector) {
            var targetNodes, btargetsFound;
            if (typeof iframeSelector == "undefined")
                targetNodes     = $(selectorTxt);
            else
                targetNodes     = $(iframeSelector).contents ()
                                                .find (selectorTxt);
    
            if (targetNodes  &&  targetNodes.length > 0) {
                btargetsFound   = true;
                targetNodes.each ( function () {
                    var jThis        = $(this);
                    var alreadyFound = jThis.data ('alreadyFound')  ||  false;
    
                    if (!alreadyFound) {
                        var cancelFound     = actionFunction (jThis);
                        if (cancelFound)
                            btargetsFound   = false;
                        else
                            jThis.data ('alreadyFound', true);
                    }
                } );
            }
            else {btargetsFound   = false;}
    
            var controlObj      = waitForKeyElements.controlObj  ||  {};
            var controlKey      = selectorTxt.replace (/[^\w]/g, "_");
            var timeControl     = controlObj [controlKey];
    
            if (btargetsFound  &&  bWaitOnce  &&  timeControl) {
                clearInterval (timeControl);
                delete controlObj [controlKey]
            }
            else {
                if ( ! timeControl) {
                    timeControl = setInterval ( function () {
                            waitForKeyElements (    selectorTxt,
                                                    actionFunction,
                                                    bWaitOnce,
                                                    iframeSelector
                                                );
                        },
                        300
                    );
                    controlObj [controlKey] = timeControl;
                }
            }
            waitForKeyElements.controlObj   = controlObj;
        }

        // Calls performRedirect when page loads
        performRedirect();
    })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址