Last active
May 14, 2017 20:30
-
-
Save RikerW/c86f5e336540e3b67e10ec75b21f8531 to your computer and use it in GitHub Desktop.
reviewstalker for mith
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Review Stalker Reloaded | |
// @namespace com.tuggy.nathan | |
// @description Reloads specified Stack Exchange review pages, opening tasks as they show up | |
// @include *://*.stackexchange.com/review* | |
// @exclude *://*.stackexchange.com/review/site-eval* | |
// @include /^https?://[^\.]*\.?stackoverflow\.com/review/ | |
// @include /^https?://[^\.]*\.?serverfault\.com/review/ | |
// @include /^https?://[^\.]*\.?superuser\.com/review/ | |
// @include /^https?://[^\.]*\.?askubuntu\.com/review/ | |
// @include /^https?://[^\.]*\.?mathoverflow\.net/review/ | |
// @include *://stackapps.net/review/* | |
// @version 1.5.26 | |
// @grant GM_openInTab | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_getResourceURL | |
// @grant GM_info | |
// @resource icon lens.png | |
// ==/UserScript== | |
const HrefBlankFavicon = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; | |
const LDomNoChildMeta = ["stackapps.net", "meta.stackexchange.com", "stackoverflow.com", "meta.stackoverflow.com"]; | |
const NamTempBase = "__RSR_TEMP__"; | |
// *** Change these millisecond intervals if desired *** | |
const MsiRoundReload = 5 * 60 * 1000, MsiReloadInQueue = 15 * 1000, MsiReloadStale = 60 * 60 * 1000; | |
// *** Change these navigation counts if desired *** | |
const NNavLoadMeta = 12, NTotalNavRecycleTab = 500; | |
var LDomSites = GM_getValue("LDomSites", "").split(","); | |
var NNavLoad = GM_getValue("NNavLoad", 1); | |
var MsiReload = Math.max(MsiRoundReload / LDomSites.length, MsiReloadInQueue); | |
var DomLoadStarted = GM_getValue("DomLoadStarted", ""); | |
GM_setValue("DomLoadStarted", ""); // Should be empty most of the time | |
var BInQueue = /\/review\/.+/.test(location.href); | |
var DomMain = location.hostname, BDomInL = LDomSites.indexOf(DomMain) > -1; | |
function BHasChildMeta(Dom) { | |
return LDomNoChildMeta.indexOf(Dom) === -1; | |
} | |
var BChildMeta = BHasChildMeta(DomMain) && DomMain.startsWith("meta."); | |
if (BChildMeta) { DomMain = DomMain.substring("meta.".length); } | |
function CheckNextPage() { | |
var BRecycleTab = history.length >= NTotalNavRecycleTab && NTotalNavRecycleTab != -1; | |
var i = LDomSites.indexOf(DomMain) + 1, DomNext = LDomSites[i % LDomSites.length]; | |
if (window.name.startsWith(NamTempBase)) { | |
window.close(); | |
return; | |
} | |
if (LDomSites.length === 0) { | |
// Nowhere to go | |
return; | |
} | |
if (i >= LDomSites.length) { | |
NNavLoad = (NNavLoad % NNavLoadMeta) + 1; | |
GM_setValue("NNavLoad", NNavLoad); | |
} | |
if (NNavLoad >= NNavLoadMeta && BHasChildMeta(DomNext)) { | |
DomNext = "meta." + DomNext; | |
} | |
var HrefNext = location.protocol + "//" + DomNext + "/review"; | |
//console.log("Next page is " + HrefNext + " at " + NNavLoad + "/" + NNavLoadMeta); | |
if (BRecycleTab) { | |
GM_setValue("DomLoadStarted", DomNext); | |
GM_openInTab(HrefNext); | |
window.close(); | |
} | |
else { | |
GM_setValue("DomLoadStarted", DomNext); | |
location.assign(HrefNext); | |
} | |
} | |
var HrefOriginalFavicon; | |
function SetFavicon(HrefIcon) { | |
var NlLinkIcon = document.querySelectorAll("link[rel*='icon']"); | |
for (let N of NlLinkIcon) { | |
if (!HrefOriginalFavicon) HrefOriginalFavicon = N.href; | |
// Remove even the mobile stuff; no, that doesn't get replaced yet | |
N.remove(); | |
} | |
var ElemLinkIcon = document.createElement("link"); | |
ElemLinkIcon.rel = "icon"; | |
ElemLinkIcon.type = "image/x-icon"; | |
ElemLinkIcon.href = HrefIcon; | |
document.head.appendChild(ElemLinkIcon); | |
} | |
function BCapped(ElemInstr) { | |
return ElemInstr && ElemInstr.textContent.startsWith("Thank you for reviewing "); | |
} | |
function BEmpty(ElemInstr) { | |
return ElemInstr && ( | |
ElemInstr.textContent.startsWith("This queue has been cleared!") || | |
ElemInstr.textContent.startsWith("There are no items for you to review, matching the filter")); | |
} | |
function BLoading() { | |
return !!document.querySelector(".review-actions .ajax-loader"); | |
} | |
var BPaused = false, TitleBase = document.title, TmrQueueStatus, DtFirstLoaded = new Date(); | |
function CheckQueueStatus() { | |
let status = document.querySelector("div.review-status"); | |
if (status) { | |
document.title = TitleBase; | |
BPaused = true; | |
} | |
else { | |
let instr = document.querySelector("span.review-instructions.infobox"); | |
if (BCapped(instr)) { | |
//setTimeout(function () { CheckNextPage(); }, 5 * 1000); | |
clearInterval(TmrQueueStatus); | |
} | |
else if (BLoading()) { | |
document.title = "β¦ " + TitleBase; | |
BPaused = true; | |
} | |
else if (BEmpty(instr)) { | |
document.title = "β " + TitleBase; | |
SetFavicon(HrefBlankFavicon); | |
BPaused = false; | |
} | |
else if ((new Date()).valueOf() - DtFirstLoaded.valueOf() < MsiReloadStale) { | |
document.title = "π " + TitleBase; | |
SetFavicon(HrefOriginalFavicon); | |
BPaused = true; | |
} | |
else { | |
// Let an aged-out review item go; if it comes back, that's fine | |
BPaused = false; | |
} | |
} | |
} | |
var NlNumAvailable = document.querySelectorAll(".dashboard-count:not(.dashboard-faded) > .dashboard-num"); | |
var NNumAll = document.querySelectorAll(".dashboard-count > .dashboard-num").length; | |
function GetLHrefToOpen() { | |
var LHref = []; | |
for (let NNumAvailable of NlNumAvailable) { | |
let SNumAvailable = NNumAvailable.title; | |
if (Number.parseInt(SNumAvailable) > 0) { | |
let NLnkAvailable = NNumAvailable.parentNode.parentNode.querySelector(".dashboard-title > a"); | |
LHref.push(NLnkAvailable.href); | |
} | |
} | |
return LHref; | |
} | |
var ElemHeader, ElemMetaLoadProgress; | |
function CreateElemMetaLoadProgress() { | |
ElemMetaLoadProgress = document.createElement("span"); | |
ElemMetaLoadProgress.style.cssFloat = "right"; | |
ElemMetaLoadProgress.style.marginTop = "1em"; | |
ElemMetaLoadProgress.style.fontSize = "0.85em"; | |
ElemMetaLoadProgress.textContent = GM_info.script.name + " v" + GM_info.script.version; | |
ElemMetaLoadProgress.textContent += "; meta load: " + NNavLoad + "/" + NNavLoadMeta; | |
if (NTotalNavRecycleTab != -1) ElemMetaLoadProgress.textContent += "; tab recycle: " + history.length + "/" + NTotalNavRecycleTab; | |
ElemHeader = document.querySelector(".subheader.tools-rev"); | |
ElemHeader.appendChild(ElemMetaLoadProgress); | |
} | |
function AddSite(Dom) { | |
if (BDomInL) return false; | |
LDomSites.push(Dom); | |
if (!LDomSites[0]) LDomSites = LDomSites.slice(1); | |
let SLDomSitesNew = LDomSites.join(","); | |
GM_setValue("LDomSites", SLDomSitesNew); | |
return true; | |
} | |
function RemoveSite(Dom) { | |
if (!BDomInL) return false; | |
let i = LDomSites.indexOf(Dom); | |
if (i > -1) { | |
LDomSites.splice(i, 1); | |
let SLDomSitesNew = LDomSites.join(",").replace(/^,|,,|,$/, ''); | |
GM_setValue("LDomSites", SLDomSitesNew); | |
return true; | |
} | |
else { | |
console.log("Unable to find site " + Dom + " to remove it in '" + LDomSites.join(",") + "'!"); | |
return false; | |
} | |
} | |
function CheckSiteMembership(NQueueAvailable, ElemContainer, ElemStatus) { | |
if (DomLoadStarted && DomMain != DomLoadStarted && RemoveSite(DomLoadStarted)) { | |
// We didn't end up where we wanted, probably because it's gone | |
ElemStatus.textContent += " β " + DomLoadStarted + " missing!"; | |
BPaused = true; | |
} else | |
if (NQueueAvailable > 0 && AddSite(DomMain)) { | |
ElemStatus.textContent += " β site added!"; | |
} | |
else if (0 === NQueueAvailable && RemoveSite(DomMain)) { | |
ElemStatus.textContent += " β site removed!"; | |
BPaused = true; | |
} | |
else if (!BDomInL) { | |
ElemContainer.removeChild(ElemStatus); | |
BPaused = true; | |
} | |
} | |
var LHrefToOpen = []; | |
if (BInQueue) { | |
if (1 === history.length) { | |
window.name = NamTempBase + Math.round(Math.random() * 1000); | |
} | |
TitleBase = document.title.replace(/^Review /, ""); | |
TmrQueueStatus = setInterval(CheckQueueStatus, 0.25 * 1000); | |
} | |
else { | |
SetFavicon(GM_getResourceURL("icon")); | |
LHrefToOpen = GetLHrefToOpen(); | |
if (NNumAll > 0 && !BChildMeta) { | |
CreateElemMetaLoadProgress(); | |
CheckSiteMembership(NlNumAvailable.length, ElemHeader, ElemMetaLoadProgress); | |
} | |
} | |
function AddPauseButton(ElemContainer, ElemMarker) { | |
var ElemPause = document.createElement("a"); | |
ElemPause.href = "#"; | |
ElemPause.style.cssFloat = "right"; | |
ElemPause.style.marginTop = "1em"; | |
ElemPause.style.marginLeft = "1em"; | |
ElemPause.textContent = BPaused ? "Resume" : "Pause"; | |
ElemPause.addEventListener("click", function (e) { | |
BPaused = !BPaused; | |
ElemPause.textContent = BPaused ? "Resume" : "Pause"; | |
if (e) e.preventDefault(); | |
return false; | |
}); | |
if (ElemMarker.parentNode) ElemMarker.parentNode.insertBefore(ElemPause, ElemMarker); | |
} | |
if (LHrefToOpen.length > 0) { | |
for (let i = BChildMeta ? 0 : 1; i < LHrefToOpen.length; i++) { | |
GM_openInTab(LHrefToOpen[i]); | |
} | |
if (BChildMeta) { | |
//CheckNextPage(); | |
} | |
else { | |
location.href = LHrefToOpen[0]; | |
} | |
} | |
else { | |
if (!BInQueue) { | |
if (BChildMeta) { | |
//CheckNextPage(); | |
} | |
else { | |
AddPauseButton(ElemHeader, ElemMetaLoadProgress); | |
} | |
} | |
let TryLoadNext = function() { | |
if (!BPaused) { | |
//CheckNextPage(); | |
} | |
}; | |
setInterval(TryLoadNext, BInQueue ? MsiReloadInQueue : MsiReload); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment