Skip to content

Instantly share code, notes, and snippets.

@jaideepheer
Last active January 17, 2022 18:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaideepheer/228d0d0a2a6ea7d01cb02292bd9ffd56 to your computer and use it in GitHub Desktop.
Save jaideepheer/228d0d0a2a6ea7d01cb02292bd9ffd56 to your computer and use it in GitHub Desktop.
Userscript Snippets
// ...
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// ...
class GM_Cyclic_Config {
constructor({
key,
values = ['OFF', 'ON'],
init_idx = 0,
render_fn=(th) => `Config ${th.key} is: ${th.value}`,
// Function run when value updates
on_update = (preValue, newValue, isNextDirection) => {},
has_UI=true,
}){
this.key = key;
this.values = values;
this._curidx = GM_getValue(key, init_idx);
this.render_fn = render_fn;
this.has_UI = has_UI;
this.on_update = on_update;
this.updateUI();
}
get value(){
return this.values[this._curidx];
}
set value(new_value){
const nidx = this.values.indexOf(new_value);
if(this._curidx == nidx)
console.log(`GM_Cyclic_Config tried to set same value '${new_value}' for key '${this.key}'`);
return;
if(nidx < 0)
console.error(`GM_Cyclic_Config tried to set invalid value '${new_value}' for key '${this.key}'`);
// Set new value
this._curidx = nidx;
GM_setValue(this.key, nidx);
// Update UI if needed
this.updateUI();
}
next(){
let prev = this.value;
this._curidx = (this._curidx + 1) % this.values.length;
GM_setValue(this.key, this._curidx);
this.updateUI();
this.on_update(prev, this.value, true);
}
previous(){
let prev = this.value;
this._curidx = (this._curidx - 1 + this.values.length) % this.values.length;
GM_setValue(this.key, this._curidx);
this.updateUI();
this.on_update(prev, this.value, false);
}
updateUI(){
if(this.has_UI == true)
{
GM_unregisterMenuCommand(this._render_cache);
GM_registerMenuCommand(this.str, () => this.next());
}
}
get str(){
this._render_cache = this.render_fn(this);
return this._render_cache;
}
}
// Rate limits promise calls evenly across a given time period
class RateLimiter {
constructor({
// Max calls in time period
maxRate,
// Total time period in milli seconds
timePeriodMillis,
}){
this.maxRate = maxRate;
this.timePeriodMillis = timePeriodMillis;
this.minDelay = timePeriodMillis / maxRate;
this._waiter = Promise.resolve();
}
then(callback) {
let prev_res = this._waiter.then(res => callback())
this._waiter = prev_res.then(_ => new Promise(
(res, rej) => setTimeout(()=>res(), this.minDelay)
)
);
return prev_res;
}
}
// ...
// @grant GM_xmlhttpRequest
// ...
// tampermonkey fetch
const tamperFetch = (url, options) => new Promise((resolve, reject) => {
options.url = url
options.onerror = (error) => reject(error)
options.onabort = () => reject("GM_xmlhttpRequest aborted.")
options.ontimeout = () => reject("GM_xmlhttpRequest timeout.")
options.onload = (...args) => resolve(...args)
GM_xmlhttpRequest(options)
})
// Waits for a condition function to == true while polling at constant intervals.
var waitCondition = (checkDelayMilli, conditionFunc, timeoutMilli = 1000) => new Promise(
(resolve, reject) => {
var flag = false;
const check_loop = setInterval(() => {
flag = conditionFunc();
if (flag == true) {
resolve()
}
}, checkDelayMilli);
setTimeout(() => {
if (flag === false) {
clearInterval(check_loop);
reject("Wait condition timed out.");
}
}, timeoutMilli);
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment