Greasy Fork

Greasy Fork is available in English.

AO3: [Wrangling] Peek at unassigned fandoms' bins!!

Peek at the sizes of the unwrangled tags on the "Fandoms in Need of a Wrangler" pages!

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         AO3: [Wrangling] Peek at unassigned fandoms' bins!!
// @description  Peek at the sizes of the unwrangled tags on the "Fandoms in Need of a Wrangler" pages!
// @version      1.0.1

// @author       owlwinter
// @namespace    N/A
// @license      MIT license

// @match        *://*.archiveofourown.org/fandoms/unassigned*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    //Set to be true if you are using the Direct Links on Unassigned Fandoms Page script
    //http://greasyfork.icu/en/scripts/435045-ao3-wrangling-direct-links-on-unassigned-fandoms-page/code
    var USING_DIRECT_LINK_SCRIPT = false;

    //Set to false if you don't want the bins to be highlighted
    var SHOW_COLORS = true;

    //Creating a simple "load bins" button
    const button = document.createElement("button")
    const buttondiv = document.createElement("div")
    buttondiv.append(button)
    document.querySelector(".fandoms").prepend(buttondiv)

    //We'll use this to pause the script if we get rate limited
    var ratelimited = false;

    //From a value 0-1, returns a color on the green-red scale
    //Where 0 will display as pure green
    //And 1 will display as pure red
    function getColor(value){
        //value from 0 to 1
        var hue=((1-value)*120).toString(10);
        return ["hsl(",hue,",60%,70%)"].join("");
    }

    // called for each of the 3 unwrangled bins in the fandoms list (char/rel/ff)
    // `url` is the url of that bin's edit page
    // `Results` is the space we are writing the count to
    const getBinCount = function getBinCount(url, results) {
        results.innerText = "Loading...!"
        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function xhr_onreadystatechange() {
            if (xhr.readyState == xhr.DONE ) {
                if (xhr.status == 200) {
                    ratelimited = false;
                    var binsize;
                    results.href = url
                    var table = xhr.responseXML.documentElement.querySelector("table")
                    var pagination = xhr.responseXML.documentElement.querySelector(".pagination")
                    if (table == null) {
                        //Nothing in this bin
                        binsize = 0;
                        results.innerText = 0;
                    } else if (pagination == null) {
                        //One page in this bin
                        binsize = table.rows.length - 1;
                        results.innerText = binsize;
                    } else {
                        //Multiple pages in this bin
                        //Gets the text of the button that leads to the last page of that bin
                        var a = xhr.responseXML.documentElement.querySelector(".pagination").querySelectorAll("li")
                        var b = xhr.responseXML.documentElement.querySelector(".pagination").querySelectorAll("li").length-2
                        var c = a[b].innerText;
                        //Max page number -1, then * 20 works per page to get the estimated size
                        //ie 3 pages would mean at least (2*20) tags in the bins
                        binsize = (parseInt(c)-1) * 20
                        results.innerText = binsize + "+"
                    }

                    //Displays highlight color
                    if (SHOW_COLORS) {
                        var normalizednum = binsize/500;
                        if (normalizednum > 1) {
                            normalizednum = 1;
                        }
                        var color = getColor(normalizednum);
                        results.parentElement.style.backgroundColor = color;
                    }

                } else if (xhr.status == 429) {
                    // ~ao3jail
                    //We will pause further queries until not rate limited
                    ratelimited = true;
                    //We'll also wait then retry this xhr request once no longer rate limited
                    waitthenretry(url, results)
                    return "Rate limited. Sorry :("
                } else {
                    return "Unexpected error, check the console :("
                    console.log(xhr)
                }
            }
        }
        xhr.open("GET", url)
        xhr.responseType = "document"
        xhr.send()
    }

    const sleep = time => new Promise(resolve => setTimeout(resolve, time));
    const array = f => Array.prototype.slice.call(f, 0)

    //After 30 seconds, we will retry the same xhr request
    async function waitthenretry(url, results) {
        results.innerText = "Retrying"
        await sleep(10000)
        results.innerText = "Retrying."
        await sleep(10000)
        results.innerText = "Retrying.."
        await sleep(10000)
        results.innerText = "Retrying...!"
        getBinCount(url, results)
    }

    //Will go through fandoms on a page, put them in a table,
    //then will make the necessary xhr requests
    async function get_unwrangleddata() {
        button.parentElement.removeChild(button);
        const fandomslist = array(document.querySelectorAll(".fandoms a"))

        var tableheaders = ["Fandom", "Characters", "Relationships", "Freeforms"]
        let table = document.createElement("table");
        let thead = table.createTHead();
        let row = thead.insertRow();
        //Adds headers to table
        for (let key of tableheaders) {
            let th = document.createElement("th");
            let text = document.createTextNode(key);
            th.appendChild(text);
            row.appendChild(th);
        }

        document.querySelector(".fandoms").innerHTML = ''
        document.querySelector(".fandoms").appendChild(table)

        //Instantly load the fandomslist in the table
        //We'll go back through each fandom later
        for (var fandom of fandomslist) {
            const tr = table.insertRow();
            const trlink = document.createElement("a")
            trlink.innerHTML = fandom.innerText;
            trlink.href = fandom.href;
            tr.appendChild(trlink)
        }

        //Now we'll go through each fandom!!
        //We'll create the cells for the resulting links
        //and counts to go
        for (let i = 1; i < table.rows.length; i++) {
            let currentrow = table.rows[i]
            let fandomlink = currentrow.querySelector("a").href

            var charbincell = currentrow.insertCell()
            var charbinlink = document.createElement("a")
            charbincell.appendChild(charbinlink)
            charbinlink.target = "_blank"
            charbinlink.style.color = "black";

            var relbincell = currentrow.insertCell()
            var relbinlink = document.createElement("a")
            relbincell.appendChild(relbinlink)
            relbinlink.target = "_blank"
            relbinlink.style.color = "black";

            var ffbincell = currentrow.insertCell()
            var ffbinlink = document.createElement("a")
            ffbincell.appendChild(ffbinlink)
            ffbinlink.target = "_blank"
            ffbinlink.style.color = "black";

            //If rate limited, prevent new xhr requests
            //Then wait until no longer rate limited to continue
            while (ratelimited) {
                charbinlink.innerText = "Paused"
                relbinlink.innerText = "Paused"
                ffbinlink.innerText = "Paused"
                await sleep(10000)
            }

            //Short delay so the servers won't hate us
            charbinlink.innerText = "Loading."
            relbinlink.innerText = "Loading."
            ffbinlink.innerText = "Loading."
            await sleep(1000)
            charbinlink.innerText = "Loading.."
            relbinlink.innerText = "Loading.."
            ffbinlink.innerText = "Loading.."
            await sleep(1000)
            charbinlink.innerText = "Loading..."
            relbinlink.innerText = "Loading..."
            ffbinlink.innerText = "Loading..."
            await sleep(1000)

            if (USING_DIRECT_LINK_SCRIPT) {
                const lastIndex = fandomlink.lastIndexOf('/');
                fandomlink = fandomlink.slice(0, lastIndex)
            }

            getBinCount(fandomlink + "/wrangle?show=characters&status=unwrangled", charbinlink)
            getBinCount(fandomlink + "/wrangle?show=relationships&status=unwrangled", relbinlink)
            getBinCount(fandomlink + "/wrangle?show=freeforms&status=unwrangled", ffbinlink)
        }
    }

    // Styles button
    button.innerText = "Show bins!"
    button.addEventListener("click", get_unwrangleddata)
    button.style.display = "inline"
    button.style.fontSize = "0.627rem"
    button.style.marginTop = "10px"

    //Making the text on the table look nicer
    const style = document.createElement("style")
    style.innerHTML = ".a:visited { color: black !important; } tr { border-bottom: 1px solid #fff !important}"
    document.head.appendChild(style)
})();