Last active
September 29, 2021 11:33
-
-
Save Kefta/558ce995ac409a39b9950f2cd6282b3a to your computer and use it in GitHub Desktop.
Run in your devtool snippets on chrome while on the DomainLink
This file contains 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
// Overengineered script to remove items from an RYM wishlist | |
const DomainLink = "rateyourmusic.com" // Base domain link | |
const WishlistLinkPath = "/collection/username/wishlist,ss.d"; // Link to the wishlist | |
const MinPageNum = 1; // inclusive, <1 == 1 | |
const MaxPageNum = 0; // inclusive, <1 == Max wishlist page | |
const MinRequestTime = 8000; // ms | |
const MaxRequestTime = 10000; | |
// Function that will be called for printing, takes one string argument | |
// Defining this as function(){} will silence all messages except for thrown exceptions | |
const OutputFunc = console.log; | |
const HaltOnNonCriticalError = true; // If true, throws exceptions even for non-critical errors | |
function Run() | |
{ | |
DeleteWishlist(WishlistLinkPath, MinPageNum, MaxPageNum, rym.session.token, MakeOutputFunc(OutputFunc, HaltOnNonCriticalError)); | |
} | |
///////////////////////////////////////////////////////////// | |
{ | |
function Strip(sLink) | |
{ | |
var aLink = sLink.match(/^([\w+]+:\/\/)?(\w+\.)?(.+?\.\w*)/); | |
if (aLink === null) throw `invalid link "${sLink}"`; | |
return aLink[3]; | |
} | |
if (Strip(window.location.href) !== Strip(DomainLink)) throw `the script must be executed while on ${DomainLink}`; | |
} | |
const OutputTypes = { | |
Begin: 0, | |
Complete: 1, | |
Wait: 2, | |
Load: 3, | |
LoadError: 4, | |
Page: 5, | |
PageError: 6, | |
Release: 7, | |
ReleaseError: 8 | |
} | |
function MakeOutputFunc(fSimpleOutput, bHaltingLoadErrors = false) | |
{ | |
return function(eOutputType, sMsg) | |
{ | |
var sPrefix = "UNKNOWN"; | |
switch(eOutputType) | |
{ | |
case OutputTypes.Begin: | |
case OutputTypes.Complete: sPrefix = "WISHLIST"; break; | |
case OutputTypes.Wait: sPrefix = "WAIT"; break; | |
case OutputTypes.Load: sPrefix = "LOAD"; break; | |
case OutputTypes.LoadError: sPrefix = "LOAD ERROR"; break; | |
case OutputTypes.Page: sPrefix = "PAGE"; break; | |
case OutputTypes.PageError: sPrefix = "PAGE ERROR"; break; | |
case OutputTypes.Release: sPrefix = "RELEASE"; break; | |
case OutputTypes.ReleaseError: sPrefix = "RELEASE ERROR"; break; | |
} | |
const sOutput = `[${sPrefix}] ${sMsg}`; | |
if (bHaltingLoadErrors && | |
(eOutputType == OutputTypes.LoadError | |
|eOutputType == OutputTypes.PageError | |
|eOutputType == OutputTypes.ReleaseError)) | |
throw sOutput; | |
fSimpleOutput(sOutput); | |
} | |
} | |
function GetRequestTime() | |
{ | |
// FIXME: Placeholder | |
return Math.floor(Math.random() * (MaxRequestTime - MinRequestTime) + MinRequestTime); | |
} | |
function MakeFetchFailureFunc(fOutput, sLink, bHaltingLoadErrors = false) | |
{ | |
return function(error) | |
{ | |
const sOutput = `failed to load page "${sLink}" with error "${error}"`; | |
if (bHaltingLoadErrors) | |
throw sOutput; | |
fOutput(OutputTypes.LoadError, sOutput); | |
} | |
} | |
function Wait(fOutput, fCallback, ...args) | |
{ | |
const unDelay = GetRequestTime(); | |
fOutput(OutputTypes.Wait, `${unDelay / 1000} seconds`); | |
setTimeout(fCallback, unDelay, ...args); | |
} | |
function ParseMax(sPage) | |
{ | |
// FIXME: Skip escaped quotes inside the href string | |
const aMatches = sPage.match(/<a\s+class\s*=\s*("navlinknum")(?!.*\1)\s+href\s*=\s*"[^"]*">\s*(\d+)\s*</); | |
if (aMatches === null) throw "failed to find max page number (navlinknum element), make sure the wishlist link is correct"; | |
const uMaxPageNum = parseInt(aMatches[2], 10); | |
if (uMaxPageNum !== uMaxPageNum) throw `failed to convert max page string "${aMatches[2]}" into number`; | |
if (uMaxPageNum < 1) throw `invalid parsed max page number $uMaxPageNum`; | |
return uMaxPageNum; | |
} | |
function UnwishlistItem(sReleaseLinkPath, sID, sToken, fOutput) | |
{ | |
fOutput(OutputTypes.Release, `unwishlisting item "${sReleaseLinkPath}" (${sID})`); | |
//rym.request.post("CatalogSetOwnership", { type: 'l', assoc_id: sID, ownership: 'n' }); | |
var data = new FormData(); | |
data.append("type", "l"); | |
data.append("assoc_id", sID); | |
data.append("ownership", "n"); | |
data.append("action", "CatalogSetOwnership") | |
data.append("rym_ajax_req", 1); | |
data.append("request_token", sToken); | |
fetch("/httprequest/CatalogSetOwnership", {method: "POST", body: data}) | |
.then(response => fOutput(OutputTypes.Release, `unwishlisted item "${sReleaseLinkPath}" (${sID}) with status ${response.status}`)) | |
.catch(error => fOutput(OutputTypes.ReleaseError, `failed to unwishlist item "${sReleaseLinkPath}" (${sID}) with error ${error}`)); | |
} | |
function ForEachItem(sWishlistLinkPath, sToken, fOutput, uCurPage, uPageCount, aReleases) | |
{ | |
const tReleaseData = aReleases.pop(); | |
const sReleaseLinkPath = tReleaseData[0]; | |
const sID = tReleaseData[1]; | |
UnwishlistItem(sReleaseLinkPath, sID, sToken, fOutput); | |
if (aReleases.length !== 0) | |
Wait(fOutput, ForEachItem, sWishlistLinkPath, sToken, fOutput, uCurPage, uPageCount, aReleases); | |
else if (uPageCount !== 0) | |
Wait(fOutput, ForEachPage, sWishlistLinkPath, sToken, fOutput, uCurPage, uPageCount); | |
else | |
fOutput(OutputTypes.Complete, "completed wishlist deletion"); | |
} | |
function ForEachPage(sWishlistLinkPath, sToken, fOutput, uCurPage, uPageCount) | |
{ | |
const sPageLinkPath = sWishlistLinkPath + "/" + uCurPage; | |
fetch(sPageLinkPath, {method: "GET"}) | |
.then(response => response.text()) | |
.then(function(sPage) | |
{ | |
// FIXME: Handle blank page | |
fOutput(OutputTypes.Load, `loaded page ${uCurPage}`); | |
// FIXME: Very lazy, will match to the next a tag outside of this tr if the pattern doesn't fit as expected | |
const rReleases = /<a\s+title\s*=\s*"\[(Album|Film)\d+\]"\s*href\s*=\s*"([^"]+)"[\s\S]+?"tagl(\d+)"/g; | |
var aReleases = [] | |
var tReleaseData | |
while (tReleaseData = rReleases.exec(sPage)) | |
{ | |
aReleases.push([tReleaseData[2], tReleaseData[3]]); | |
} | |
if (aReleases.length == 0) | |
{ | |
fOutput(OutputTypes.PageError, `page ${uCurPage} is empty or matching failed`); | |
Wait(fOutput, ForEachPage, sWishlistLinkPath, sToken, fOutput, uCurPage - 1, uPageCount - 1); | |
} | |
else | |
{ | |
fOutput(OutputTypes.Page, `processing page ${uCurPage}`); | |
Wait(fOutput, ForEachItem, sWishlistLinkPath, sToken, fOutput, uCurPage - 1, uPageCount - 1, aReleases); | |
} | |
}) | |
.catch(MakeFetchFailureFunc(fOutput, sPageLinkPath)); | |
} | |
function DeleteWishlist(sWishlistLinkPath, uMinPageNum, uMaxPageNum, sToken, fOutput) | |
{ | |
const aWishlistLinkPath = sWishlistLinkPath.match(/^(.+)[\\\/]*$/); | |
if (aWishlistLinkPath === null) throw `invalid wishlist link path "${sWishlistLinkPath}"`; | |
sWishlistLinkPath = aWishlistLinkPath[1]; | |
uMinPageNum = uMinPageNum = uMinPageNum < 1 ? 1 : Math.floor(uMinPageNum); | |
uMaxPageNum = Math.floor(uMaxPageNum); | |
if (uMaxPageNum < 1) | |
{ | |
fetch(sWishlistLinkPath, {method: "GET"}) | |
.then(response => response.text()) | |
.then(function(sPage) | |
{ | |
uMaxPageNum = ParseMax(sPage); | |
if (uMinPageNum > uMaxPageNum) throw `MinPageNum (${uMinPageNum}) is greater than the number of pages left in the wishlist (${uMaxPageNum})`; | |
fOutput(OutputTypes.Begin, `beginning wishlist deletion for pages ${uMinPageNum} to ${uMaxPageNum}`); | |
// FIXME: Handle having no wishlist pages | |
Wait(fOutput, ForEachPage, sWishlistLinkPath, sToken, fOutput, uMaxPageNum, uMaxPageNum - uMinPageNum + 1); | |
}) | |
.catch(MakeFetchFailureFunc(fOutput, sWishlistLinkPath)); | |
} | |
else | |
{ | |
if (uMinPageNum > uMaxPageNum) throw `MinPageNum (${uMinPageNum}) is greater than MaxPageNum (${uMaxPageNum})`; | |
fOutput(OutputTypes.Begin, `beginning wishlist deletion for pages ${uMinPageNum} to ${uMaxPageNum}`); | |
ForEachPage(sWishlistLinkPath, sToken, fOutput, uMaxPageNum, uMaxPageNum - uMinPageNum + 1); | |
} | |
} | |
///////////////////////////////////////////////////////////// | |
Run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment