Background Pony #BFC6
I have some proposed revisions:
const booruDefault = {
...
forbiddenRedirPath: '/', //new
hasTagError: (str) => { //is this the best way to do this? I dunno, I'm barely a hobbyist
const dom = new DOMParser().parseFromString(str, 'text/html');
return {
errored: [...dom.getElementsByClassName('alert-danger')]
.some((ele) => ele.textContent.includes('Oops, something went wrong!')),
messages: [...dom.getElementsByClassName('help-block')]
.map((ele) => ele.textContent),
}; },
async function throttle(fn, ...args) {
...
try { //because we're throwing errors around
const result = await new Promise(resolve => {
window.setTimeout(() => {
resolve(fn(...args));
}, timeRemain);
});
GM_setValue(key, Date.now());
return result;
} finally {
GM_setValue(key, Date.now()); //still need to do this while throwing errors around
}
async function bulkApplyTags(tagsToAdd, tagsToRemove) {
...
await throttle(submitEdit, id, oldTags, newTags);
} catch (err) {
errors += 1;
// Also do stuff like styling thumbnails based on what the specific error is
} finally {
async function submitEdit(id, oldTags, newTags) {
...
const abort = new AbortController(); //new
const resp = await fetch(path, {
method: 'POST',
body: form,
signal: abort.signal, //new
});
if (resp.status !== 200) {
throw new Error('status code: ' + resp.status);
} else if (resp.redirected) { //all new
abort.abort();
if ((window.location.origin + getBooruParam('forbiddenRedirPath')) == (resp.url))
throw new Error('forbidden');
else
throw new Error('redirected');
}
const body = await resp.text();
const errors = getBooruParam('hasTagError')(body);
if (errors.errored) throw new Error('prevented', { cause: errors.messages });
The abort is because there’s no reason to load Derpibooru’s index page if tagging fails, saving 30-some KB, which is nothing in this day and age but it’s the principle of it…
1. If the tag change is rejected, count it as an error:
- Although it could be thought of as “successfully failing” ie. working as intended vs. an error, not applying a change is an event a user* might want to follow up on.
*me- Future features: highlight the images that the errors occurred on, with styles uniquely communicating which kind of failure occurred for them.
- If the tag change is prevented due to permissions (such as tags being locked), philomena currently responds with a 302 redirect to ‘/’.
fetch
will resolve it as a status 200 with.redirect
= true and.url
aslocation.origin + '/'
- I don’t see a way to know that a post’s tags are locked via the API or the data on the thumbnails page:
- It can be found out in the aforementioned way, or
- It could be found out by making yet another fetch, for the image’s page itself (not its API) and looking for
<div class=\"js-imageform hidden\"><p>You can't edit the tags on this image. </p></div>
.
- I don’t see a way to know that a post’s tags are locked via the API or the data on the thumbnails page:
- If the tag change is prevented due to ratelimit violation, philomena responds with a 302 redirect to the
referer
- I couldn’t figure out a way to get the string that will be sent as the referrer without making a lot of janky assumptions;
window.location.origin + window.location.pathname + window.location.search
seems to be the default…but perhaps some other user extension would alter that, and I couldn’t find a way to get the actualreferer
string that will be sent byfetch
’sRequest
- it just returnsabout:client
verbatim. - So, instead, test for
resp.redirected
and hope that no other philomena implementation uses redirects for successful API responses.
- I couldn’t figure out a way to get the string that will be sent as the referrer without making a lot of janky assumptions;
- Throw unique errors in these cases. As mentioned above, it might be nice to present which images encountered tagging errors, and what sort of tagging error (as you might just try again if it’s a network or ratelimit violation, vs. pursuing mod assistance with tag locked images.)
2. If the tag change is invalid, eg. trying to assign both
safe
and suggestive
, philomena rejects the entire attempt and that should also be detected as an error.- When trying to apply invalid tags combos from the normal web form, the response contains a bunch of HTML (to replace certain elements on the page) and includes text like
Oops, something went wrong! Please check the errors below.
which could be detected.However, for reasons I can’t figure out, when making the requests through the userscript, even if I set all the headers and payload to be exactly the same, I find response body is empty/absent.Looks like a quirk(?) of the Chrome network tab - if I await and access resp.text() in the script, suddenly the response shows up.Any idea why that is? Currently, I don’t have an idea how to detect that type of failure.- Instead, the tag validation could be re-created to proactively perform on the client-side in lieu of looking for it in responses.