Greasy Fork

Greasy Fork is available in English.

Kickass Torrents Enhancements with Ad Remover

Enhances KickassTorrents (KAT) by forcing HTTPS, using a max-width layout, enabling navigation in search results using the arrow keys and removing ads.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Kickass Torrents Enhancements with Ad Remover
// @id          kickass-enhancements
// @namespace   urn:uuid:53d8a5b1-8677-481a-8096-939db3c8d0b3
// @version     1.7.10
// @description Enhances KickassTorrents (KAT) by forcing HTTPS, using a max-width layout, enabling navigation in search results using the arrow keys and removing ads.
// @license     MIT; http://opensource.org/licenses/MIT
// @include     http://kat.cr/*
// @include     https://kat.cr/*
// @grant       unsafeWindow
// @run-at      document-start
// ==/UserScript==

(function () {
    "use strict";

    var katObjectFound;
    var contentContainer;
    var sidebar;
    var prevPageHref;
    var nextPageHref;
    var hideSidebar;
    var showSidebar;

    (function () {
        // Force HTTPS
        if (/^http:\/\//.test(window.location.href)) {
            // Hide document during redirection
            var style = document.createElement("style");
            style.type = "text/css";
            style.textContent = "* { display: none; }";

            var parent = document.documentElement || document;
            parent.appendChild(style);

            // Redirect to HTTPS
            window.location.replace(window.location.href.replace(/^http:\/\//, "https://"));
            return;
        }

        // Adblock code
        var code = function (unsafeWindow, exportFunction) {
            // Prevent overwriting
            var Error = window.Error;
            var HTMLAnchorElement = window.HTMLAnchorElement;
            var querySelector = document.querySelector.bind(document);

            // Break the script creating advertisements
            var _scq = exportFunction(function _scq() {
                throw new Error("Advertisements are disabled");
            }, unsafeWindow);

            Object.defineProperty(unsafeWindow, "_scq", {
                configurable: false,
                enumerable: false,
                get: _scq,
                set: _scq
            });

            unsafeWindow.sc = exportFunction(function sc() { }, unsafeWindow);

            // Disable pop-up windows
            function isSelf(target) {
                if (target === "_self")
                    return true;

                if (target !== "")
                    return false;

                var base = querySelector("base[target]");
                if (!base)
                    return true;

                if (base.target === "" || base.target === "_self")
                    return true;

                return false;
            }

            // Prevent opening pop-up windows using window.open()
            var prevOpen = window.open;
            prevOpen = prevOpen.apply.bind(prevOpen);
            unsafeWindow.open = exportFunction(function open(href, target) {
                if (target !== "_self")
                    return null;

                return prevOpen(this, arguments);
            }, unsafeWindow);

            // Prevent opening pop-up windows using a.click()
            var prevClick = HTMLElement.prototype.click;
            prevClick = prevClick.apply.bind(prevClick);
            unsafeWindow.HTMLElement.prototype.click = exportFunction(function click() {
                if (this instanceof HTMLAnchorElement && !isSelf(this.target))
                    return;

                return prevClick(this, arguments);
            }, unsafeWindow);

            // Prevent opening pop-up windows using a.dispatchEvent()
            var prevDispatchEvent = EventTarget.prototype.dispatchEvent;
            prevDispatchEvent = prevDispatchEvent.apply.bind(prevDispatchEvent);
            unsafeWindow.EventTarget.prototype.dispatchEvent = exportFunction(function dispatchEvent(event) {
                if (this instanceof HTMLAnchorElement && event && event.type === "click" && !isSelf(this.target))
                    return;

                return prevDispatchEvent(this, arguments);
            }, unsafeWindow);
        };

        if (typeof unsafeWindow !== "undefined" && typeof exportFunction !== "undefined" && unsafeWindow !== window) {
            // Execute code in user script security context
            code(unsafeWindow, exportFunction);
        } else {
            // Execute code in page script security context
            executeCode("(" + code.toString() + ")(window, function (func) { return func; });");
        }

        var code = function () {
            // Avoid warning about getPreventDefault() being deprecated
            Event.prototype.getPreventDefault = function getPreventDefault() { return this.defaultPrevented };

            // Define jQuery property
            var jQueryValue = window.jQuery;

            Object.defineProperty(window, "jQuery", {
                configurable: true,
                enumerable: true,
                get: function jQuery() {
                    return jQueryValue;
                },
                set: function jQuery(value) {
                    // Disable jQuery Migrate logging
                    if (!("migrateMute" in value))
                        value.migrateMute = true;

                    delete window.jQuery;
                    window.jQuery = value;
                }
            });
        };
        executeCode("(" + code.toString() + ")();");

        // Ignore errors in the script creating advertisements
        window.addEventListener("error", onError, true);

        // Prevent advertisements from being created
        if ("onbeforescriptexecute" in document)
            window.addEventListener("beforescriptexecute", onBeforeScriptExecute, true);

        // Continue when DOM is available
        window.addEventListener("DOMContentLoaded", onContentLoaded, true);
    })();

    // Execute code in document context
    function executeCode(code) {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.textContent = '"use strict";\n' + code;

        var parent = document.documentElement || document;
        parent.appendChild(script);
        parent.removeChild(script);
    }

    function onError(event) {
        if (!/Advertisements are disabled/.test(event.message))
            return;

        var script = document.evaluate("descendant::*[last()]/self::script", document, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
        if (!script)
            return;

        // Match the script creating advertisements
        var code = script.textContent;
        if (!/\b_scq\b/.test(code))
            return;

        // Create kat object
        if (!katObjectFound) {
            var match = code.match(/;\s*(var\s+kat\s*=\s*{(\w|\s|[:,'"])*}\s*;)/);
            if (match) {
                katObjectFound = true;
                executeCode(match[1]);
            }
        }

        // Prevent error from being logged
        event.preventDefault();
        event.stopPropagation();
    }

    function onBeforeScriptExecute(event) {
        // Ignore external scripts
        var script = event.target;
        if (script.src !== "")
            return;

        // Prevent advertisements from being created
        var code = script.textContent;
        if (!/\b_scq\b/.test(code))
            return;

        // Create kat object
        if (!katObjectFound) {
            var match = code.match(/;\s*(var\s+kat\s*=\s*{(\w|\s|[:,'"])*}\s*;)/);
            if (match) {
                katObjectFound = true;
                executeCode(match[1]);
            }
        }

        // Prevent script from executing
        event.preventDefault();
        event.stopPropagation();
    }

    function onContentLoaded() {
        window.removeEventListener("DOMContentLoaded", onContentLoaded, true);

        if ("onbeforescriptexecute" in document)
            window.removeEventListener("beforescriptexecute", onBeforeScriptExecute, true);

        window.removeEventListener("error", onError, true);

        // Force HTTPS for links
        var items = document.querySelectorAll('a[href^="http://kat.cr/"], link[href^="http://kat.cr/"], a[href^="http://torcache.net/"], a[href^="http://torrentz.eu/"]');
        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            item.href = item.href.replace(/^http:\/\//, "https://");
        }

        // Inline referrer anonymizer (for IMDb links)
        var items = document.querySelectorAll('a[href^="http://blankrefer.com/?http"]');
        for (var i = 0; i < items.length; i++) {
            var a = items[i];
            var match = a.href.match(/^http:\/\/blankrefer\.com\/\?(https?:\/\/.*)$/);
            if (!match)
                continue;

            var encodedURL = match[1].replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
            var html = '<meta content="0;url=' + encodedURL + '" http-equiv="refresh">';

            // Specify UTF-8 for non-ASCII characters
            var charset = "";
            if (/[^\x00-\x7f]/.test(html))
                charset = ";charset=utf-8";

            a.href = "data:text/html" + charset + "," + encodeURIComponent(html);
        }

        // Apply style sheet to support the max-width layout
        var style = document.createElement("style");
        style.type = "text/css";
        style.textContent = 'body { min-width: 0; }' +
            'footer { width: auto; }' +
            'iframe[style*="visibility:hidden"], iframe[style*="visibility: hidden"] { display: none; }' +
            '.tabs { overflow: visible; }' +
            'ul.tabNavigation li a span { padding-left: 7px; padding-right: 7px; }' +
            '.pages a:not(.blank) { min-width: 15px; padding-left: 7px; padding-right: 7px; }';
        document.head.appendChild(style);

        // Select original content container
        var mainContent = document.querySelector(".mainpart .doublecelltable td");
        sidebar = document.querySelector("#sidebar");
        if (!mainContent && !sidebar)
            mainContent = document.querySelector(".mainpart");

        // Create max-width content container
        if (mainContent) {
            contentContainer = document.createElement("div");
            contentContainer.style.margin = "15px auto 0";
            contentContainer.style.maxWidth = "900px";

            while (mainContent.firstChild)
                contentContainer.appendChild(mainContent.firstChild);

            // Include float elements in parent height
            var clearDiv = document.createElement("div");
            clearDiv.style.clear = "both";
            contentContainer.appendChild(clearDiv);

            mainContent.appendChild(contentContainer);

            // Remove width from nested content containers
            var items = contentContainer.querySelectorAll(':scope > div.margauto[class*="width"]');
            for (var i = 0; i < items.length; i++) {
                var item = items[i];
                if (/(^|\s)width\d{3,}px($|\s)/.test(item.className))
                    item.style.setProperty("width", "auto", "important");
            }
        }

        // Remove advertisements
        var items = document.querySelectorAll("div[data-sc-slot]");
        for (var i = 0; i < items.length; i++) {
            var item = items[i];

            // Remove line breaks after advertisement
            var br;
            while (br = document.evaluate("following-sibling::*[1]/self::br", item, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue) {
                for (var prevNode = br.previousSibling; prevNode; prevNode = prevNode.previousSibling) {
                    switch (prevNode.nodeType) {
                        case 1 /*ELEMENT_NODE*/:
                            // Found previous element
                            br.remove();
                            break;
                        case 3 /*TEXT_NODE*/:
                            // Ignore white space
                            if (!/\S/.test(prevNode.textContent))
                                continue;

                            // Found text between the line break and the previous element
                            br = null;
                            break;
                        default:
                            // Ignore comments
                            continue;
                    }

                    break;
                }

                if (br == null)
                    break;
            }

            // Remove container with margins and legend
            var parent = document.evaluate("parent::div[contains(concat(' ', normalize-space(@class), ' '), ' spareBlock ')]", item, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
            if (parent)
                parent.remove();

            item.remove();
        }

        // Remove single tabs with no content (Sponsored Links)
        var items = document.querySelectorAll(".tabs");
        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            if (!item.querySelector(":scope > :not(.tabNavigation):not(.tabsSeparator)") && document.evaluate("not(descendant::li[2])", item, null, 3 /*BOOLEAN_TYPE*/, null).booleanValue)
                item.remove();
        }

        // Enhance navigation
        var activePages = document.querySelectorAll(".pages a.active");
        for (var i = 0; i < activePages.length; i++) {
            var activePage = activePages[i];
            var parent = activePage.parentNode;

            // Ignore non-navigational pages
            if (!/^[0-9]+$/.test(activePage.textContent))
                continue;

            // Add Prev button
            var prevPage = document.evaluate("preceding-sibling::a[not(contains(concat(' ', normalize-space(@class), ' '), ' kaTurnoverButton '))][1]", activePage, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
            if (prevPage) {
                if (i === 0)
                    prevPageHref = prevPage.href;

                prevPage = prevPage.cloneNode(false);
                prevPage.textContent = "< Prev";

                var firstPage = document.evaluate("preceding-sibling::a[not(contains(concat(' ', normalize-space(@class), ' '), ' kaTurnoverButton '))][last()]", activePage, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
                parent.insertBefore(prevPage, firstPage);
            }

            // Add Next button
            var nextPage = document.evaluate("following-sibling::a[not(contains(concat(' ', normalize-space(@class), ' '), ' kaTurnoverButton '))][1]", activePage, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
            if (nextPage) {
                if (i === 0)
                    nextPageHref = nextPage.href;

                nextPage = nextPage.cloneNode(false);
                nextPage.textContent = "Next >";

                var lastPage = document.evaluate("following-sibling::a[not(contains(concat(' ', normalize-space(@class), ' '), ' kaTurnoverButton '))][last()]", activePage, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
                parent.insertBefore(nextPage, lastPage.nextSibling);
            }
        }

        // Navigate using arrow keys
        if (prevPageHref || nextPageHref)
            window.addEventListener("keypress", onKeyPress, false);

        // Restore removed torrents
        var alertField = contentContainer && contentContainer.querySelector(":scope > .alertfield");
        if (alertField) {
            var torrentHashSpan = document.querySelector("#tab-technical .lightgrey");
            if (torrentHashSpan) {
                var match = torrentHashSpan.textContent.match(/\b[A-Z0-9]{40}\b/);
                if (match) {
                    var torrentHash = match[0];

                    alertField.style.margin = "10px auto";

                    // Adjust alert message
                    var alertText = alertField.querySelector("h2");
                    if (alertText && !alertText.firstElementChild)
                        alertText.textContent = alertText.textContent.replace(/\band not available for download\b/, "and only Magnet link is available");

                    // Add Magnet link button
                    if (!document.querySelector(".magnetlinkButton")) {
                        var magnetLink = "magnet:?xt=urn:btih:" + encodeURIComponent(torrentHash);

                        var match = window.location.pathname.match(/^\/(.*)-[^-]*$/);
                        if (match) {
                            var torrentName = match[1];
                            magnetLink = magnetLink + "&dn=" + encodeURIComponent(torrentName);
                        }

                        var verifiedDiv = document.evaluate("following-sibling::*[1][contains(concat(' ', normalize-space(@class), ' '), ' lightgrey ')]", alertField, null, 8 /*ANY_UNORDERED_NODE_TYPE*/, null).singleNodeValue;
                        var isVerified = verifiedDiv && /\bTorrent verified\b/.test(verifiedDiv.textContent);

                        // Add button container
                        var buttonsLine = document.createElement("div");
                        buttonsLine.classList.add("buttonsline");
                        buttonsLine.classList.add("downloadButtonGroup");
                        buttonsLine.classList.add("clearleft");
                        buttonsLine.classList.add("novertpad");

                        // Add button
                        var magnetLinkButton = document.createElement("a");
                        magnetLinkButton.classList.add("siteButton");
                        magnetLinkButton.classList.add("giantButton");
                        if (isVerified)
                            magnetLinkButton.classList.add("verifTorrentButton");
                        magnetLinkButton.href = magnetLink;
                        magnetLinkButton.title = isVerified ? "Verified Magnet link" : "Magnet link";
                        buttonsLine.appendChild(magnetLinkButton);

                        // Add button text
                        var magnetLinkButtonText = document.createElement("span");
                        magnetLinkButtonText.textContent = "Magnet link";
                        magnetLinkButton.appendChild(magnetLinkButtonText);

                        // Add verified image
                        if (isVerified) {
                            var magnetLinkButtonPic = document.createElement("em");
                            magnetLinkButtonPic.classList.add("buttonPic");
                            magnetLinkButtonText.insertBefore(magnetLinkButtonPic, magnetLinkButtonText.firstChild);
                        }

                        alertField.parentNode.insertBefore(buttonsLine, alertField.nextSibling);
                    }
                }
            }
        }

        if (sidebar) {
            hideSidebar = document.querySelector("#hidesidebar");
            showSidebar = document.querySelector("#showsidebar");

            // Create sidebar toggles
            if (!hideSidebar || !showSidebar) {
                if (hideSidebar)
                    hideSidebar.parentNode.removeChild(hideSidebar);

                if (showSidebar)
                    showSidebar.parentNode.removeChild(showSidebar);

                sidebar.classList.add("sidebarLogged");
                sidebar.classList.add("font11px");

                // Create hideSidebar
                hideSidebar = document.createElement("a");
                hideSidebar.id = "hidesidebar";
                hideSidebar.classList.add("hideSidebar");
                hideSidebar.addEventListener("click", onHideSidebarClick, false);

                // Create showSidebar
                showSidebar = document.createElement("a");
                showSidebar.id = "showsidebar";
                showSidebar.classList.add("showSidebar");
                showSidebar.style.display = "none";
                showSidebar.addEventListener("click", onShowSidebarClick, false);

                // Insert sidebar toggles
                sidebar.parentNode.insertBefore(hideSidebar, sidebar);
                sidebar.parentNode.insertBefore(showSidebar, sidebar);
            }

            var items = sidebar.querySelectorAll(".sliderbox");
            var i = items.length - 1;
            while (i >= 0) {
                var section = items[i--];

                var sectionHeader = section.querySelector("h3");
                if (!sectionHeader)
                    continue;

                var foldClose = sectionHeader.querySelector(".foldClose");
                if (!foldClose)
                    continue;

                var block = section.querySelector(".showBlockJS");
                if (!block)
                    continue;

                // Enable toggling sidebar section by clicking on the section header
                sectionHeader.style.cursor = "pointer";
                sectionHeader.addEventListener("click", onSectionHeaderClick, false);

                // Close sidebar sections while the viewport is shorter than the document and sidebar is higher than content
                if (contentContainer && window.innerWidth > document.documentElement.clientWidth && sidebar.offsetTop + sidebar.offsetHeight > contentContainer.offsetTop + contentContainer.offsetHeight) {
                    foldClose.classList.remove("ka-arrow2-up");
                    foldClose.classList.add("ka-arrow2-down");
                    block.classList.remove("showBlockJS");
                    block.classList.add("hideBlockJS");
                }
            }
        }
    }

    function onKeyPress(event) {
        var newLocation;

        switch (event.key) {
            case "Left":
            case "ArrowLeft":
                if (!prevPageHref)
                    return;

                newLocation = prevPageHref;
                break;
            case "Right":
            case "ArrowRight":
                if (!nextPageHref)
                    return;

                newLocation = nextPageHref;
                break;
            default:
                return;
        }

        var activeElement = document.activeElement;
        if (activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement)
            return;

        event.preventDefault();

        window.location.assign(newLocation);
    }

    function onHideSidebarClick(event) {
        sidebar.style.display = "none";
        hideSidebar.style.display = "none";
        showSidebar.style.display = "";

        event.preventDefault();
    }

    function onShowSidebarClick(event) {
        sidebar.style.display = "";
        hideSidebar.style.display = "";
        showSidebar.style.display = "none";

        event.preventDefault();
    }

    function onSectionHeaderClick(event) {
        var sectionHeader = event.target;

        // Ignore events bubbling from children
        if (sectionHeader !== event.currentTarget)
            return;

        var foldClose = sectionHeader.querySelector(".foldClose");
        if (!foldClose)
            return;

        foldClose.click();
        event.preventDefault();
    }

})();