您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Highlight a bin on the Wrangling Home if the oldest tag in it is overdue
当前为
// ==UserScript== // @name AO3: [Wrangling] Highlight Bins with Overdue Tags // @namespace https://greasyfork.org/en/users/906106-escctrl // @description Highlight a bin on the Wrangling Home if the oldest tag in it is overdue // @author escctrl // @version 0.1 // @match *://*.archiveofourown.org/tag_wranglers/* // @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js // @license MIT // ==/UserScript== // ******* CONFIGURATION OPTIONS ******* // set which fandoms should be checked // options: "" = all, "solo" = solo-wrangled, or "shared" = co-wrangled // this works only if you already use one of the filtering scripts: // - "Wrangling Filter Redux" at https://greasyfork.org/scripts/381543 // - "n-in-1 Filters" at https://greasyfork.org/en/scripts/430805 // if you're using other filtering scripts, or none at all, it will always age-check all unwrangled bins var filter_fandoms = "solo"; // add here how you'd like the link and/or the cell to appear, e.g. bold text on the link, yellow cell background color const css_link = "font-weight: bold;"; const css_cell = ""; // set age at which tags are considered overdue, e.g. 14 days or 1 month const max_age_days = 0; const max_age_months = 1; // wait duration between checking individual bins - set this number higher if you often run into Retry Later // defined in milliseconds, e.g. 3000 = 3 seconds const interval = 3000; // ******* ********************* ******* (function($) { // for later comparison, the current date - 1 month const agedOut = createDate(max_age_days*-1, max_age_months*-1, 0); // some CSS to make aged-out links bold $('<style type="text/css"> td.has_agedout a { '+ css_link +' } td.has_agedout { ' + css_cell + ' } #agecheck-container { font-size: smaller; } </style>').appendTo($('head')); // we need to wait for the document to finish loading, so the added paragraph from the filtering scripts has loaded $(document).ready(function(){ 'use strict'; // sanitize config - depending on filtering script, find the corresponding css classes var filters_appl = $('.assigned tbody tr'); switch (filter_fandoms) { case "solo": if ($(filters_appl).filter('.solo-fandom').length > 0) { filter_fandoms = '.solo-fandom'; } // standard and redux else if ($(filters_appl).filter('.solo-wrangled').length > 0) { filter_fandoms = '.solo-wrangled'; } // n-in-1 break; case "shared": if ($(filters_appl).filter('.shared-fandom').length > 0) { filter_fandoms = '.shared-fandom'; } // standard and redux else if ($(filters_appl).filter('.co-wrangled').length > 0) { filter_fandoms = '.co-wrangled'; } // n-in-1 break; default: filter_fandoms = ''; break; } // Add a link to the page $('.assigned p:first-of-type').append(' • <span id="agecheck-container"><a id="agecheck-fandom">check for overdue tags</a></span><span id="agecheck-jail" style="display: none;">false</span>'); // assign the function to the click event (will trigger only once user clicked the link) $('.assigned p a#agecheck-fandom').click(runAgeCheck); }); // is triggered on click of the link function runAgeCheck() { // remove the link so it can't be pressed again var agecheck_progress = $('.assigned p #agecheck-container'); $(agecheck_progress).html("checking age..."); // select the bins which should be checked (config) and have unwrangled tags (contain an <a> element) var bins = $('.assigned tbody tr'+ filter_fandoms +' td[title~="unwrangled"]').has('a'); // update user on progress with X of Y message $(agecheck_progress).append(' <span id="agecheck-loop"></span> of ' + $(bins).length); // loop through the unwrangled bins $(bins).each(function(i, bin) { // set a delay between bin checks to reduce chances of jail setTimeout(function() { // if previous loops hit Ao3 Jail, don't try checking age anymore if ( $('.assigned p #agecheck-jail').text() == "true") { console.log('previously received "Retry later" response, skipped check on bin #'+i); return false; } // update user on progress $(agecheck_progress).find('#agecheck-loop').text(i+1); // need to be sure the URL is "pure" and hasn't been edited by other scripts // [0] is now the /tags/FANDOM/wrangle // [1] is the rest which contains the filters and sort orders var binLink = $(bin).find("a").attr("href").split("?"); // find the show=X and status=X parts of the URL which we'll need for our check // then join the whole thing back together - the bin and parameters we need in the URL binLink = binLink[0] + "?" + binLink[1].match(/(show=\w*|status=\w*)/ig).join("&"); // load the bin's first page sorted by age $.get(binLink + '&sort_column=created_at&sort_direction=ASC', function(response) { // nothing to do here, all interactions are in done() and failed() }).done(function(response) { // from the response, pick the first row/tag and check it's created date var tagCreated = new Date($(response).find('#wrangulator tbody tr:first-of-type td[title="created"]').text()); // if creation date is older than our maximum allowed age, add a CSS class to the row and the cell if (tagCreated < agedOut) { $(bin).addClass('has_agedout'); $(bin).parent().addClass('has_agedout'); } // thanks to Przemysław Sienkiewicz on Stackoverflow for the code to catch error responses https://stackoverflow.com/a/40256829 }).fail(function(data, textStatus, xhr) { //This shows status code eg. 429 console.log("bin #"+i+" error", data.status); //This shows status message eg. Too Many Requests //console.log("bin #"+i+" STATUS: "+xhr); // update user on the issue $(agecheck_progress).html('age check has hit "Retry later", sorry!'); $('.assigned p #agecheck-jail').text("true"); // set it in DOM so next delayed loops can skip return false; }); if (bins.length == i+1) { // progress update to user: last iteration, we're done! $('.assigned p #agecheck-container').html("age check complete"); } // the each() loops immediately and creates all timeout calls (async) at once, so we need to stagger them // by multiplying the 3s delay by the loop number (bin #0 = 3000*0, bin #1 = 3000*1, bin #2 = 3000*2, etc) }, interval*i); }); } })(jQuery); // convenience function to be able to pass minus values into a Date, so JS will automatically shift correctly over month/year boundaries // thanks to Phil on Stackoverflow for the code snippet https://stackoverflow.com/a/37003268 function createDate(days, months, years) { var date = new Date(); date.setFullYear(date.getFullYear() + years); date.setMonth(date.getMonth() + months); date.setDate(date.getDate() + days); return date; }