Last active
May 11, 2022 14:27
-
-
Save Alistair1231/1efc6138988425c938e6289736ada85d to your computer and use it in GitHub Desktop.
My Userscripts
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 0bin.net auto-select never expire | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1 | |
// @description auto selects never expire when making a paste | |
// @author Alistair1231 | |
// @match https://0bin.net/ | |
// @grant none | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/0binExpire.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
document.getElementById("expiration").value="never"; | |
// Your code here... | |
})(); |
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 Anilist links on MAL | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1 | |
// @description adds anilist links to mal | |
// @author Alistair1231 | |
// @match https://myanimelist.net/anime/* | |
// @icon https://icons.duckduckgo.com/ip2/anilist.co.ico | |
// @grant none | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/Anilist-links-on-MAL.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function (window, undefined) { | |
let jQ = jQuery; | |
console.log("in run"); | |
let anidb = document.createElement('a'); | |
anidb.href="https://duckduckgo.com/?q=!ducky+" + $(".title-name.h1_bold_none strong")[0].innerHTML + "+site%3Aanilist.co%2Fanime"; | |
anidb.target="_blank"; | |
anidb.innerHTML="Anilist"; | |
let myDiv= jQ("h2:contains(\"External Links\")").next(); | |
jQ(myDiv).append(", ") | |
jQ(myDiv).append(anidb); | |
})(window); |
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 Anilist more links (MAL/AniDB) | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.4 | |
// @description adds links to anilist/mal site to anilist (uses just the duckduckgo I'm feeling ducky feature with the anime name) | |
// @author Alistair1231 | |
// @match https://anilist.co/* | |
// @icon https://icons.duckduckgo.com/ip2/anilist.co.ico | |
// @grant GM_addStyle | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/anilist-more-links.user.js | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// ==/UserScript== | |
//Shim for MutationObserver interface | |
{/*! | |
* Shim for MutationObserver interface | |
* Author: Graeme Yeates (github.com/megawac) | |
* Repository: https://github.com/megawac/MutationObserver.js | |
* License: WTFPL V2, 2004 (wtfpl.net). | |
* Though credit and staring the repo will make me feel pretty, you can modify and redistribute as you please. | |
* Attempts to follow spec (http:// www.w3.org/TR/dom/#mutation-observers) as closely as possible for native javascript | |
* See https://github.com/WebKit/webkit/blob/master/Source/WebCore/dom/MutationObserver.cpp for current webkit source c++ implementation | |
*/ | |
/** | |
* prefix bugs: | |
- https://bugs.webkit.org/show_bug.cgi?id=85161 | |
- https://bugzilla.mozilla.org/show_bug.cgi?id=749920 | |
* Don't use WebKitMutationObserver as Safari (6.0.5-6.1) use a buggy implementation | |
*/ | |
window.MutationObserver = window.MutationObserver || window.MozMutationObserver || (function (undefined) { | |
'use strict'; | |
/** | |
* @param {function(Array.<MutationRecord>, MutationObserver)} listener | |
* @constructor | |
*/ | |
function MutationObserver(listener) { | |
/** | |
* @type {Array.<Object>} | |
* @private | |
*/ | |
this._watched = []; | |
/** @private */ | |
this._listener = listener; | |
} | |
/** | |
* Start a recursive timeout function to check all items being observed for mutations | |
* @type {MutationObserver} observer | |
* @private | |
*/ | |
function startMutationChecker(observer) { | |
(function check() { | |
var mutations = observer.takeRecords(); | |
if (mutations.length) // fire away | |
// calling the listener with context is not spec but currently consistent with FF and WebKit | |
observer._listener(mutations, observer); | |
/** @private */ | |
observer._timeout = setTimeout(check, MutationObserver._period); | |
})(); | |
} | |
/** | |
* Period to check for mutations (~32 times/sec) | |
* @type {number} | |
* @expose | |
*/ | |
MutationObserver._period = 30; /*ms+runtime*/ | |
/** | |
* Exposed API | |
* @expose | |
* @final | |
*/ | |
MutationObserver.prototype = { | |
/** | |
* see http:// dom.spec.whatwg.org/#dom-mutationobserver-observe | |
* not going to throw here but going to follow the current spec config sets | |
* @param {Node|null} $target | |
* @param {Object|null} config : MutationObserverInit configuration dictionary | |
* @expose | |
* @return undefined | |
*/ | |
observe: function ($target, config) { | |
/** | |
* Using slightly different names so closure can go ham | |
* @type {!Object} : A custom mutation config | |
*/ | |
var settings = { | |
attr: !!(config.attributes || config.attributeFilter || config.attributeOldValue), | |
// some browsers are strict in their implementation that config.subtree and childList must be set together. We don't care - spec doesn't specify | |
kids: !!config.childList, descendents: !!config.subtree, | |
charData: !!(config.characterData || config.characterDataOldValue) | |
}, watched = this._watched; | |
// remove already observed target element from pool | |
for (var i = 0; i < watched.length; i++) | |
if (watched[i].tar === $target) watched.splice(i, 1); | |
if (config.attributeFilter) | |
/** | |
* converts to a {key: true} dict for faster lookup | |
* @type {Object.<String,Boolean>} | |
*/ | |
settings.afilter = reduce(config.attributeFilter, function (a, b) { | |
a[b] = true; | |
return a; | |
}, {}); | |
watched.push({ | |
tar: $target, | |
fn: createMutationSearcher($target, settings) | |
}); | |
// reconnect if not connected | |
if (!this._timeout) startMutationChecker(this); | |
}, | |
/** | |
* Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once | |
* @expose | |
* @return {Array.<MutationRecord>} | |
*/ | |
takeRecords: function () { | |
var mutations = [], watched = this._watched, wl = watched.length; | |
for (var i = 0; i < wl; i++) watched[i].fn(mutations); | |
return mutations; | |
}, | |
/** | |
* @expose | |
* @return undefined | |
*/ | |
disconnect: function () { | |
this._watched = []; // clear the stuff being observed | |
clearTimeout(this._timeout); // ready for garbage collection | |
/** @private */ | |
this._timeout = null; | |
} | |
}; | |
/** | |
* Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant | |
* @param {Object} data | |
* @return {Object} a MutationRecord | |
*/ | |
function MutationRecord(data) { | |
var settings = { // technically these should be on proto so hasOwnProperty will return false for non explicitly set props | |
type: null, target: null, addedNodes: [], removedNodes: [], previousSibling: null, | |
nextSibling: null, attributeName: null, attributeNamespace: null, oldValue: null | |
}; | |
for (var prop in data) | |
if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop]; | |
return settings; | |
} | |
/** | |
* Creates a func to find all the mutations | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function createMutationSearcher($target, config) { | |
/** type {Elestuct} */ | |
var $oldstate = clone($target, config); // create the cloned datastructure | |
/** | |
* consumes array of mutations we can push to | |
* | |
* @param {Array.<MutationRecord>} mutations | |
*/ | |
return function (mutations) { | |
var olen = mutations.length, dirty; | |
// Alright we check base level changes in attributes... easy | |
if (config.attr && $oldstate.attr) | |
findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter); | |
// check childlist or subtree for mutations | |
if (config.kids || config.descendents) | |
dirty = searchSubtree(mutations, $target, $oldstate, config); | |
// reclone data structure if theres changes | |
if (dirty || mutations.length !== olen) | |
/** type {Elestuct} */ | |
$oldstate = clone($target, config); | |
}; | |
} | |
/* attributes + attributeFilter helpers */ | |
/** | |
* fast helper to check to see if attributes object of an element has changed | |
* doesnt handle the textnode case | |
* | |
* @param {Array.<MutationRecord>} mutations | |
* @param {Node} $target | |
* @param {Object.<string, string>} $oldstate : Custom attribute clone data structure from clone | |
* @param {Object} filter | |
*/ | |
function findAttributeMutations(mutations, $target, $oldstate, filter) { | |
var checked = {}, attributes = $target.attributes, i = attributes.length, attr, name; | |
while (i--) { | |
attr = attributes[i]; | |
name = attr.name; | |
if (!filter || has(filter, name)) { | |
if (attr.value !== $oldstate[name]) | |
// The pushing is redundant but gzips very nicely | |
mutations.push(MutationRecord({ | |
type: 'attributes', target: $target, attributeName: name, oldValue: $oldstate[name], | |
attributeNamespace: attr.namespaceURI // in ie<8 it incorrectly will return undefined | |
})); | |
checked[name] = true; | |
} | |
} | |
for (name in $oldstate) | |
if (!(checked[name]) && $oldstate.hasOwnProperty(name)) | |
mutations.push(MutationRecord({ target: $target, type: 'attributes', attributeName: name, oldValue: $oldstate[name] })); | |
} | |
/** | |
* searchSubtree: array of mutations so far, element, element clone, bool | |
* synchronous dfs comparision of two nodes | |
* This function is applied to any observed element with childList or subtree specified | |
* Sorry this is kind of confusing as shit, tried to comment it a bit... | |
* codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func | |
* | |
* @param {Array} mutations | |
* @param {Node} $target | |
* @param {!Object} $oldstate : A custom cloned node from clone() | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function searchSubtree(mutations, $target, $oldstate, config) { | |
// Track if the tree is dirty and has to be recomputed (#14). | |
var dirty; | |
/* | |
* Helper to identify node rearrangment and stuff... | |
* There is no gaurentee that the same node will be identified for both added and removed nodes | |
* if the positions have been shuffled. | |
* conflicts array will be emptied by end of operation | |
*/ | |
function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) { | |
// the distance between the first conflicting node and the last | |
var distance = conflicts.length - 1, | |
// prevents same conflict being resolved twice consider when two nodes switch places. | |
// only one should be given a mutation event (note -~ is used as a math.ceil shorthand) | |
counter = -~((distance - numAddedNodes) / 2), $cur, oldstruct, conflict; | |
while (conflict = conflicts.pop()) { | |
$cur = $kids[conflict.i]; | |
oldstruct = $oldkids[conflict.j]; | |
// attempt to determine if there was node rearrangement... won't gaurentee all matches | |
// also handles case where added/removed nodes cause nodes to be identified as conflicts | |
if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, addedNodes: [$cur], removedNodes: [$cur], | |
// haha don't rely on this please | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
counter--; // found conflict | |
} | |
// Alright we found the resorted nodes now check for other types of mutations | |
if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// now look @ subtree | |
if (config.descendents) findMutations($cur, oldstruct); | |
} | |
} | |
/** | |
* Main worker. Finds and adds mutations if there are any | |
* @param {Node} node | |
* @param {!Object} old : A cloned data structure using internal clone | |
*/ | |
function findMutations(node, old) { | |
var $kids = node.childNodes, $oldkids = old.kids, klen = $kids.length, | |
// $oldkids will be undefined for text and comment nodes | |
olen = $oldkids ? $oldkids.length : 0; | |
// if (!olen && !klen) return; // both empty; clearly no changes | |
// we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused) | |
// map of checked element of ids to prevent registering the same conflict twice | |
var map, | |
// array of potential conflicts (ie nodes that may have been re arranged) | |
conflicts, id, // element id from getElementId helper | |
idx, // index of a moved or inserted element | |
oldstruct, | |
// current and old nodes | |
$cur, $old, | |
// track the number of added nodes so we can resolve conflicts more accurately | |
numAddedNodes = 0, | |
// iterate over both old and current child nodes at the same time | |
i = 0, j = 0; | |
// while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;) | |
while (i < klen || j < olen) { | |
// current and old nodes at the indexs | |
$cur = $kids[i]; | |
oldstruct = $oldkids[j]; | |
$old = oldstruct && oldstruct.node; | |
if ($cur === $old) { // expected case - optimized for this case | |
// check attributes as specified by config | |
if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */ findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
// check character data if node is a comment or textNode and it's being observed | |
if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// resolve conflicts; it will be undefined if there are no conflicts - otherwise an array | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
// recurse on next level of children. Avoids the recursive call when there are no children left to iterate | |
if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct); | |
i++; | |
j++; | |
} else { // (uncommon case) lookahead until they are the same again or the end of children | |
dirty = true; | |
if (!map) { // delayed initalization (big perf benefit) | |
map = {}; | |
conflicts = []; | |
} | |
if ($cur) { | |
// check id is in the location map otherwise do a indexOf search | |
if (!(map[id = getElementId($cur)])) { // to prevent double checking | |
// mark id as found | |
map[id] = true; | |
// custom indexOf using comparitor checking oldkids[i].node === $cur | |
if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, | |
addedNodes: [$cur], // $cur is a new node | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
numAddedNodes++; | |
} | |
else conflicts.push({ i: i, j: idx }); // add conflict | |
} | |
i++; | |
} | |
if ($old && | |
// special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case | |
$old !== $kids[i] | |
) { | |
if (!(map[id = getElementId($old)])) { | |
map[id] = true; | |
if ((idx = indexOf($kids, $old, i)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: old.node, removedNodes: [$old], | |
nextSibling: $oldkids[j + 1], // praise no indexoutofbounds exception | |
previousSibling: $oldkids[j - 1] | |
})); | |
numAddedNodes--; | |
} | |
else conflicts.push({ i: idx, j: j }); | |
} | |
j++; | |
} | |
}// end uncommon case | |
}// end loop | |
// resolve any remaining conflicts | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
} | |
findMutations($target, $oldstate); | |
return dirty; | |
} | |
/** | |
* Utility | |
* Clones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012 | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
* @return {!Object} : Cloned data structure | |
*/ | |
function clone($target, config) { | |
var recurse = true; // set true so childList we'll always check the first level | |
return (function copy($target) { | |
var elestruct = {/** @type {Node} */ node: $target }; | |
// Store current character data of target text or comment node if the config requests | |
// those properties to be observed. | |
if (config.charData && ($target.nodeType === 3 || $target.nodeType === 8)) | |
elestruct.charData = $target.nodeValue; | |
// its either a element, comment, doc frag or document node | |
else { | |
// Add attr only if subtree is specified or top level and avoid if | |
// attributes is a document object (#13). | |
if (config.attr && recurse && $target.nodeType === 1) | |
/** | |
* clone live attribute list to an object structure {name: val} | |
* @type {Object.<string, string>} | |
*/ | |
elestruct.attr = reduce($target.attributes, function (memo, attr) { | |
if (!config.afilter || config.afilter[attr.name]) | |
memo[attr.name] = attr.value; | |
return memo; | |
}, {}); | |
// whether we should iterate the children of $target node | |
if (recurse && ((config.kids || config.charData) || (config.attr && config.descendents))) | |
/** @type {Array.<!Object>} : Array of custom clone */ | |
elestruct.kids = map($target.childNodes, copy); | |
recurse = config.descendents; | |
} | |
return elestruct; | |
}($target)); | |
} | |
/** | |
* indexOf an element in a collection of custom nodes | |
* | |
* @param {NodeList} set | |
* @param {!Object} $node : A custom cloned node | |
* @param {number} idx : index to start the loop | |
* @return {number} | |
*/ | |
function indexOfCustomNode(set, $node, idx) { | |
return indexOf(set, $node, idx, JSCompiler_renameProperty('node')); | |
} | |
// using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like <li></li> | |
var counter = 1, // don't use 0 as id (falsy) | |
/** @const */ | |
expando = 'mo_id'; | |
/** | |
* Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern | |
* | |
* @param {Node} $ele | |
* @return {(string|number)} | |
*/ | |
function getElementId($ele) { | |
try { | |
return $ele.id || ($ele[expando] = $ele[expando] || counter++); | |
} catch (o_O) { // ie <8 will throw if you set an unknown property on a text node | |
try { | |
return $ele.nodeValue; // naive | |
} catch (shitie) { // when text node is removed: https://gist.github.com/megawac/8355978 :( | |
return counter++; | |
} | |
} | |
} | |
/** | |
* **map** Apply a mapping function to each item of a set | |
* @param {Array|NodeList} set | |
* @param {Function} iterator | |
*/ | |
function map(set, iterator) { | |
var results = [], sl = set.length; | |
for (var index = 0; index < sl; index++) | |
results[index] = iterator(set[index], index, set); | |
return results; | |
} | |
/** | |
* **Reduce** builds up a single result from a list of values | |
* @param {Array|NodeList|NamedNodeMap} set | |
* @param {Function} iterator | |
* @param {*} [memo] Initial value of the memo. | |
*/ | |
function reduce(set, iterator, memo) { | |
var sl = set.length; | |
for (var index = 0; index < sl; index++) | |
memo = iterator(memo, set[index], index, set); | |
return memo; | |
} | |
/** | |
* **indexOf** find index of item in collection. | |
* @param {Array|NodeList} set | |
* @param {Object} item | |
* @param {number} idx | |
* @param {string} [prop] Property on set item to compare to item | |
*/ | |
function indexOf(set, item, idx, prop) { | |
var sl = set.length; | |
for (/*idx = ~~idx*/; idx < sl; idx++) // start idx is always given as this is internal | |
if ((prop ? set[idx][prop] : set[idx]) === item) return idx; | |
return -1; | |
} | |
/** | |
* @param {Object} obj | |
* @param {(string|number)} prop | |
* @return {boolean} | |
*/ | |
function has(obj, prop) { | |
return obj[prop] !== undefined; // will be nicely inlined by gcc | |
} | |
// GCC hack see http://stackoverflow.com/a/23202438/1517919 | |
function JSCompiler_renameProperty(a) { | |
return a; | |
} | |
return MutationObserver; | |
}()); | |
} | |
//////////////// | |
var isReady=0; | |
function run() { | |
console.log("in run"); | |
// if no external links there, add the div to the sidebar | |
if(jQuery("div.external-links h2~div").length==0) { | |
var myDiv=document.createElement("div"); | |
jQuery(myDiv).attr({"data-v-7a1f9df8":"","data-v-1c97ba07":"","class":"external-links"}); | |
myDiv.innerHTML="<h2 data-v-7a1f9df8=\"\">External & Streaming links<\/h2><div data-v-7a1f9df8=\"\" class=\"external-links-wrap\"><\/div>"; | |
jQuery("div.sidebar")[0].appendChild(myDiv); | |
} | |
var linkBar = jQuery("div.external-links h2~div"); | |
var name = jQuery(".content h1")[0].innerText; | |
var mal = "https://duckduckgo.com/?q=!ducky+" + name + "+site%3Amyanimelist.net%2Fanime"; | |
var malButton = createButton(mal, "MAL"); | |
var anidb = "https://duckduckgo.com/?q=!ducky+" + name + "+site%3Aanidb.net+inurl%3Aanime%2F"; | |
var anidbButton = createButton(anidb, "AniDB"); | |
if (jQuery("a.external-link[href*='https://duckduckgo.']").length == 0) { | |
linkBar.prepend(malButton); | |
linkBar.prepend(anidbButton); | |
} | |
} | |
function createButton(link, name) { | |
var a = document.createElement("a"); | |
jQuery(a).attr("data-v-7a1f9df8", ""); | |
a.href = link; | |
a.target = "_blank"; | |
jQuery(a).addClass("external-link"); | |
a.innerHTML = name; | |
// make purple | |
jQuery(a).css("background", "rgb(150, 59, 241)"); | |
return a; | |
} | |
(function (window, undefined) { | |
let lastUrl = location.href; | |
isReady = setInterval(checkReady, 100); | |
new MutationObserver(() => { | |
const url = location.href; | |
if (url !== lastUrl) { | |
lastUrl = url; | |
console.log("url changed"); | |
isReady = setInterval(checkReady(isReady), 100); | |
} | |
}).observe(document, { subtree: true, childList: true }); | |
function checkReady() { | |
if (jQuery(".content h1")[0]) { | |
clearInterval(isReady); | |
isReady=null; | |
console.log("in checkReady"); | |
run(); | |
} | |
} | |
})(window); |
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
|
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 faloop.app copy map locations | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1.1 | |
// @description copy map location when clicked | |
// @author Alistair1231 | |
// @match https://faloop.app/* | |
// @icon https://icons.duckduckgo.com/ip2/faloop.app.ico | |
// @grant none | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/faloop-app-copy-map-locations.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
{/*! | |
* Shim for MutationObserver interface | |
* Author: Graeme Yeates (github.com/megawac) | |
* Repository: https://github.com/megawac/MutationObserver.js | |
* License: WTFPL V2, 2004 (wtfpl.net). | |
* Though credit and staring the repo will make me feel pretty, you can modify and redistribute as you please. | |
* Attempts to follow spec (http:// www.w3.org/TR/dom/#mutation-observers) as closely as possible for native javascript | |
* See https://github.com/WebKit/webkit/blob/master/Source/WebCore/dom/MutationObserver.cpp for current webkit source c++ implementation | |
*/ | |
/** | |
* prefix bugs: | |
- https://bugs.webkit.org/show_bug.cgi?id=85161 | |
- https://bugzilla.mozilla.org/show_bug.cgi?id=749920 | |
* Don't use WebKitMutationObserver as Safari (6.0.5-6.1) use a buggy implementation | |
*/ | |
window.MutationObserver = window.MutationObserver || window.MozMutationObserver || (function (undefined) { | |
'use strict'; | |
/** | |
* @param {function(Array.<MutationRecord>, MutationObserver)} listener | |
* @constructor | |
*/ | |
function MutationObserver(listener) { | |
/** | |
* @type {Array.<Object>} | |
* @private | |
*/ | |
this._watched = []; | |
/** @private */ | |
this._listener = listener; | |
} | |
/** | |
* Start a recursive timeout function to check all items being observed for mutations | |
* @type {MutationObserver} observer | |
* @private | |
*/ | |
function startMutationChecker(observer) { | |
(function check() { | |
var mutations = observer.takeRecords(); | |
if (mutations.length) // fire away | |
// calling the listener with context is not spec but currently consistent with FF and WebKit | |
observer._listener(mutations, observer); | |
/** @private */ | |
observer._timeout = setTimeout(check, MutationObserver._period); | |
})(); | |
} | |
/** | |
* Period to check for mutations (~32 times/sec) | |
* @type {number} | |
* @expose | |
*/ | |
MutationObserver._period = 30; /*ms+runtime*/ | |
/** | |
* Exposed API | |
* @expose | |
* @final | |
*/ | |
MutationObserver.prototype = { | |
/** | |
* see http:// dom.spec.whatwg.org/#dom-mutationobserver-observe | |
* not going to throw here but going to follow the current spec config sets | |
* @param {Node|null} $target | |
* @param {Object|null} config : MutationObserverInit configuration dictionary | |
* @expose | |
* @return undefined | |
*/ | |
observe: function ($target, config) { | |
/** | |
* Using slightly different names so closure can go ham | |
* @type {!Object} : A custom mutation config | |
*/ | |
var settings = { | |
attr: !!(config.attributes || config.attributeFilter || config.attributeOldValue), | |
// some browsers are strict in their implementation that config.subtree and childList must be set together. We don't care - spec doesn't specify | |
kids: !!config.childList, descendents: !!config.subtree, | |
charData: !!(config.characterData || config.characterDataOldValue) | |
}, watched = this._watched; | |
// remove already observed target element from pool | |
for (var i = 0; i < watched.length; i++) | |
if (watched[i].tar === $target) watched.splice(i, 1); | |
if (config.attributeFilter) | |
/** | |
* converts to a {key: true} dict for faster lookup | |
* @type {Object.<String,Boolean>} | |
*/ | |
settings.afilter = reduce(config.attributeFilter, function (a, b) { | |
a[b] = true; | |
return a; | |
}, {}); | |
watched.push({ | |
tar: $target, | |
fn: createMutationSearcher($target, settings) | |
}); | |
// reconnect if not connected | |
if (!this._timeout) startMutationChecker(this); | |
}, | |
/** | |
* Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once | |
* @expose | |
* @return {Array.<MutationRecord>} | |
*/ | |
takeRecords: function () { | |
var mutations = [], watched = this._watched, wl = watched.length; | |
for (var i = 0; i < wl; i++) watched[i].fn(mutations); | |
return mutations; | |
}, | |
/** | |
* @expose | |
* @return undefined | |
*/ | |
disconnect: function () { | |
this._watched = []; // clear the stuff being observed | |
clearTimeout(this._timeout); // ready for garbage collection | |
/** @private */ | |
this._timeout = null; | |
} | |
}; | |
/** | |
* Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant | |
* @param {Object} data | |
* @return {Object} a MutationRecord | |
*/ | |
function MutationRecord(data) { | |
var settings = { // technically these should be on proto so hasOwnProperty will return false for non explicitly set props | |
type: null, target: null, addedNodes: [], removedNodes: [], previousSibling: null, | |
nextSibling: null, attributeName: null, attributeNamespace: null, oldValue: null | |
}; | |
for (var prop in data) | |
if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop]; | |
return settings; | |
} | |
/** | |
* Creates a func to find all the mutations | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function createMutationSearcher($target, config) { | |
/** type {Elestuct} */ | |
var $oldstate = clone($target, config); // create the cloned datastructure | |
/** | |
* consumes array of mutations we can push to | |
* | |
* @param {Array.<MutationRecord>} mutations | |
*/ | |
return function (mutations) { | |
var olen = mutations.length, dirty; | |
// Alright we check base level changes in attributes... easy | |
if (config.attr && $oldstate.attr) | |
findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter); | |
// check childlist or subtree for mutations | |
if (config.kids || config.descendents) | |
dirty = searchSubtree(mutations, $target, $oldstate, config); | |
// reclone data structure if theres changes | |
if (dirty || mutations.length !== olen) | |
/** type {Elestuct} */ | |
$oldstate = clone($target, config); | |
}; | |
} | |
/* attributes + attributeFilter helpers */ | |
/** | |
* fast helper to check to see if attributes object of an element has changed | |
* doesnt handle the textnode case | |
* | |
* @param {Array.<MutationRecord>} mutations | |
* @param {Node} $target | |
* @param {Object.<string, string>} $oldstate : Custom attribute clone data structure from clone | |
* @param {Object} filter | |
*/ | |
function findAttributeMutations(mutations, $target, $oldstate, filter) { | |
var checked = {}, attributes = $target.attributes, i = attributes.length, attr, name; | |
while (i--) { | |
attr = attributes[i]; | |
name = attr.name; | |
if (!filter || has(filter, name)) { | |
if (attr.value !== $oldstate[name]) | |
// The pushing is redundant but gzips very nicely | |
mutations.push(MutationRecord({ | |
type: 'attributes', target: $target, attributeName: name, oldValue: $oldstate[name], | |
attributeNamespace: attr.namespaceURI // in ie<8 it incorrectly will return undefined | |
})); | |
checked[name] = true; | |
} | |
} | |
for (name in $oldstate) | |
if (!(checked[name]) && $oldstate.hasOwnProperty(name)) | |
mutations.push(MutationRecord({ target: $target, type: 'attributes', attributeName: name, oldValue: $oldstate[name] })); | |
} | |
/** | |
* searchSubtree: array of mutations so far, element, element clone, bool | |
* synchronous dfs comparision of two nodes | |
* This function is applied to any observed element with childList or subtree specified | |
* Sorry this is kind of confusing as shit, tried to comment it a bit... | |
* codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func | |
* | |
* @param {Array} mutations | |
* @param {Node} $target | |
* @param {!Object} $oldstate : A custom cloned node from clone() | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function searchSubtree(mutations, $target, $oldstate, config) { | |
// Track if the tree is dirty and has to be recomputed (#14). | |
var dirty; | |
/* | |
* Helper to identify node rearrangment and stuff... | |
* There is no gaurentee that the same node will be identified for both added and removed nodes | |
* if the positions have been shuffled. | |
* conflicts array will be emptied by end of operation | |
*/ | |
function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) { | |
// the distance between the first conflicting node and the last | |
var distance = conflicts.length - 1, | |
// prevents same conflict being resolved twice consider when two nodes switch places. | |
// only one should be given a mutation event (note -~ is used as a math.ceil shorthand) | |
counter = -~((distance - numAddedNodes) / 2), $cur, oldstruct, conflict; | |
while (conflict = conflicts.pop()) { | |
$cur = $kids[conflict.i]; | |
oldstruct = $oldkids[conflict.j]; | |
// attempt to determine if there was node rearrangement... won't gaurentee all matches | |
// also handles case where added/removed nodes cause nodes to be identified as conflicts | |
if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, addedNodes: [$cur], removedNodes: [$cur], | |
// haha don't rely on this please | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
counter--; // found conflict | |
} | |
// Alright we found the resorted nodes now check for other types of mutations | |
if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// now look @ subtree | |
if (config.descendents) findMutations($cur, oldstruct); | |
} | |
} | |
/** | |
* Main worker. Finds and adds mutations if there are any | |
* @param {Node} node | |
* @param {!Object} old : A cloned data structure using internal clone | |
*/ | |
function findMutations(node, old) { | |
var $kids = node.childNodes, $oldkids = old.kids, klen = $kids.length, | |
// $oldkids will be undefined for text and comment nodes | |
olen = $oldkids ? $oldkids.length : 0; | |
// if (!olen && !klen) return; // both empty; clearly no changes | |
// we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused) | |
// map of checked element of ids to prevent registering the same conflict twice | |
var map, | |
// array of potential conflicts (ie nodes that may have been re arranged) | |
conflicts, id, // element id from getElementId helper | |
idx, // index of a moved or inserted element | |
oldstruct, | |
// current and old nodes | |
$cur, $old, | |
// track the number of added nodes so we can resolve conflicts more accurately | |
numAddedNodes = 0, | |
// iterate over both old and current child nodes at the same time | |
i = 0, j = 0; | |
// while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;) | |
while (i < klen || j < olen) { | |
// current and old nodes at the indexs | |
$cur = $kids[i]; | |
oldstruct = $oldkids[j]; | |
$old = oldstruct && oldstruct.node; | |
if ($cur === $old) { // expected case - optimized for this case | |
// check attributes as specified by config | |
if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */ findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
// check character data if node is a comment or textNode and it's being observed | |
if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// resolve conflicts; it will be undefined if there are no conflicts - otherwise an array | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
// recurse on next level of children. Avoids the recursive call when there are no children left to iterate | |
if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct); | |
i++; | |
j++; | |
} else { // (uncommon case) lookahead until they are the same again or the end of children | |
dirty = true; | |
if (!map) { // delayed initalization (big perf benefit) | |
map = {}; | |
conflicts = []; | |
} | |
if ($cur) { | |
// check id is in the location map otherwise do a indexOf search | |
if (!(map[id = getElementId($cur)])) { // to prevent double checking | |
// mark id as found | |
map[id] = true; | |
// custom indexOf using comparitor checking oldkids[i].node === $cur | |
if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, | |
addedNodes: [$cur], // $cur is a new node | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
numAddedNodes++; | |
} | |
else conflicts.push({ i: i, j: idx }); // add conflict | |
} | |
i++; | |
} | |
if ($old && | |
// special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case | |
$old !== $kids[i] | |
) { | |
if (!(map[id = getElementId($old)])) { | |
map[id] = true; | |
if ((idx = indexOf($kids, $old, i)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: old.node, removedNodes: [$old], | |
nextSibling: $oldkids[j + 1], // praise no indexoutofbounds exception | |
previousSibling: $oldkids[j - 1] | |
})); | |
numAddedNodes--; | |
} | |
else conflicts.push({ i: idx, j: j }); | |
} | |
j++; | |
} | |
}// end uncommon case | |
}// end loop | |
// resolve any remaining conflicts | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
} | |
findMutations($target, $oldstate); | |
return dirty; | |
} | |
/** | |
* Utility | |
* Clones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012 | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
* @return {!Object} : Cloned data structure | |
*/ | |
function clone($target, config) { | |
var recurse = true; // set true so childList we'll always check the first level | |
return (function copy($target) { | |
var elestruct = {/** @type {Node} */ node: $target }; | |
// Store current character data of target text or comment node if the config requests | |
// those properties to be observed. | |
if (config.charData && ($target.nodeType === 3 || $target.nodeType === 8)) | |
elestruct.charData = $target.nodeValue; | |
// its either a element, comment, doc frag or document node | |
else { | |
// Add attr only if subtree is specified or top level and avoid if | |
// attributes is a document object (#13). | |
if (config.attr && recurse && $target.nodeType === 1) | |
/** | |
* clone live attribute list to an object structure {name: val} | |
* @type {Object.<string, string>} | |
*/ | |
elestruct.attr = reduce($target.attributes, function (memo, attr) { | |
if (!config.afilter || config.afilter[attr.name]) | |
memo[attr.name] = attr.value; | |
return memo; | |
}, {}); | |
// whether we should iterate the children of $target node | |
if (recurse && ((config.kids || config.charData) || (config.attr && config.descendents))) | |
/** @type {Array.<!Object>} : Array of custom clone */ | |
elestruct.kids = map($target.childNodes, copy); | |
recurse = config.descendents; | |
} | |
return elestruct; | |
}($target)); | |
} | |
/** | |
* indexOf an element in a collection of custom nodes | |
* | |
* @param {NodeList} set | |
* @param {!Object} $node : A custom cloned node | |
* @param {number} idx : index to start the loop | |
* @return {number} | |
*/ | |
function indexOfCustomNode(set, $node, idx) { | |
return indexOf(set, $node, idx, JSCompiler_renameProperty('node')); | |
} | |
// using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like <li></li> | |
var counter = 1, // don't use 0 as id (falsy) | |
/** @const */ | |
expando = 'mo_id'; | |
/** | |
* Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern | |
* | |
* @param {Node} $ele | |
* @return {(string|number)} | |
*/ | |
function getElementId($ele) { | |
try { | |
return $ele.id || ($ele[expando] = $ele[expando] || counter++); | |
} catch (o_O) { // ie <8 will throw if you set an unknown property on a text node | |
try { | |
return $ele.nodeValue; // naive | |
} catch (shitie) { // when text node is removed: https://gist.github.com/megawac/8355978 :( | |
return counter++; | |
} | |
} | |
} | |
/** | |
* **map** Apply a mapping function to each item of a set | |
* @param {Array|NodeList} set | |
* @param {Function} iterator | |
*/ | |
function map(set, iterator) { | |
var results = [], sl = set.length; | |
for (var index = 0; index < sl; index++) | |
results[index] = iterator(set[index], index, set); | |
return results; | |
} | |
/** | |
* **Reduce** builds up a single result from a list of values | |
* @param {Array|NodeList|NamedNodeMap} set | |
* @param {Function} iterator | |
* @param {*} [memo] Initial value of the memo. | |
*/ | |
function reduce(set, iterator, memo) { | |
var sl = set.length; | |
for (var index = 0; index < sl; index++) | |
memo = iterator(memo, set[index], index, set); | |
return memo; | |
} | |
/** | |
* **indexOf** find index of item in collection. | |
* @param {Array|NodeList} set | |
* @param {Object} item | |
* @param {number} idx | |
* @param {string} [prop] Property on set item to compare to item | |
*/ | |
function indexOf(set, item, idx, prop) { | |
var sl = set.length; | |
for (/*idx = ~~idx*/; idx < sl; idx++) // start idx is always given as this is internal | |
if ((prop ? set[idx][prop] : set[idx]) === item) return idx; | |
return -1; | |
} | |
/** | |
* @param {Object} obj | |
* @param {(string|number)} prop | |
* @return {boolean} | |
*/ | |
function has(obj, prop) { | |
return obj[prop] !== undefined; // will be nicely inlined by gcc | |
} | |
// GCC hack see http://stackoverflow.com/a/23202438/1517919 | |
function JSCompiler_renameProperty(a) { | |
return a; | |
} | |
return MutationObserver; | |
}()); | |
} | |
//////////////// | |
(function (window, undefined) { | |
'use strict'; | |
new MutationObserver(() => { | |
// blue dots | |
jQuery("div[class^=ZoneMap_poi] div span[class*=blue]").each(function () { | |
// add click event | |
jQuery(this).click(function () { | |
// copy value to clipboard | |
navigator.clipboard.writeText($(this).attr("data-pr-tooltip")) | |
}); | |
}); | |
// aetherytes | |
jQuery("div[class^=ZoneMap_poi] span[class*=aether]").each(function () { | |
// add click event | |
jQuery(this).click(function () { | |
// copy value to clipboard | |
navigator.clipboard.writeText($(this).attr("data-pr-tooltip")) | |
}); | |
}); | |
}).observe(document, { subtree: true, childList: true }); | |
})(window); |
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 Fitgirl repacks bigger images/center-alignment and 1080p optimization | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.5.0 | |
// @description bigger images/center-alignment and 1080p optimization | |
// @author Alistair1231 | |
// @match https://fitgirl-repacks.site/* | |
// @icon https://icons.duckduckgo.com/ip2/fitgirl-repacks.site.ico | |
// @grant none | |
// @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
///////////////////////////////////// | |
///////////////////////////////////// | |
// TODO FIX https://fitgirl-repacks.site/not-for-broadcast/ | |
///////////////////////////////////// | |
///////////////////////////////////// | |
// Shim for MutationObserver interface | |
{/*! | |
* Shim for MutationObserver interface | |
* Author: Graeme Yeates (github.com/megawac) | |
* Repository: https://github.com/megawac/MutationObserver.js | |
* License: WTFPL V2, 2004 (wtfpl.net). | |
* Though credit and staring the repo will make me feel pretty, you can modify and redistribute as you please. | |
* Attempts to follow spec (http:// www.w3.org/TR/dom/#mutation-observers) as closely as possible for native javascript | |
* See https://github.com/WebKit/webkit/blob/master/Source/WebCore/dom/MutationObserver.cpp for current webkit source c++ implementation | |
*/ | |
/** | |
* prefix bugs: | |
- https://bugs.webkit.org/show_bug.cgi?id=85161 | |
- https://bugzilla.mozilla.org/show_bug.cgi?id=749920 | |
* Don't use WebKitMutationObserver as Safari (6.0.5-6.1) use a buggy implementation | |
*/ | |
window.MutationObserver = window.MutationObserver || window.MozMutationObserver || (function (undefined) { | |
'use strict'; | |
/** | |
* @param {function(Array.<MutationRecord>, MutationObserver)} listener | |
* @constructor | |
*/ | |
function MutationObserver(listener) { | |
/** | |
* @type {Array.<Object>} | |
* @private | |
*/ | |
this._watched = []; | |
/** @private */ | |
this._listener = listener; | |
} | |
/** | |
* Start a recursive timeout function to check all items being observed for mutations | |
* @type {MutationObserver} observer | |
* @private | |
*/ | |
function startMutationChecker(observer) { | |
(function check() { | |
var mutations = observer.takeRecords(); | |
if (mutations.length) // fire away | |
// calling the listener with context is not spec but currently consistent with FF and WebKit | |
observer._listener(mutations, observer); | |
/** @private */ | |
observer._timeout = setTimeout(check, MutationObserver._period); | |
})(); | |
} | |
/** | |
* Period to check for mutations (~32 times/sec) | |
* @type {number} | |
* @expose | |
*/ | |
MutationObserver._period = 30; /*ms+runtime*/ | |
/** | |
* Exposed API | |
* @expose | |
* @final | |
*/ | |
MutationObserver.prototype = { | |
/** | |
* see http:// dom.spec.whatwg.org/#dom-mutationobserver-observe | |
* not going to throw here but going to follow the current spec config sets | |
* @param {Node|null} $target | |
* @param {Object|null} config : MutationObserverInit configuration dictionary | |
* @expose | |
* @return undefined | |
*/ | |
observe: function ($target, config) { | |
/** | |
* Using slightly different names so closure can go ham | |
* @type {!Object} : A custom mutation config | |
*/ | |
var settings = { | |
attr: !!(config.attributes || config.attributeFilter || config.attributeOldValue), | |
// some browsers are strict in their implementation that config.subtree and childList must be set together. We don't care - spec doesn't specify | |
kids: !!config.childList, descendents: !!config.subtree, | |
charData: !!(config.characterData || config.characterDataOldValue) | |
}, watched = this._watched; | |
// remove already observed target element from pool | |
for (var i = 0; i < watched.length; i++) | |
if (watched[i].tar === $target) watched.splice(i, 1); | |
if (config.attributeFilter) | |
/** | |
* converts to a {key: true} dict for faster lookup | |
* @type {Object.<String,Boolean>} | |
*/ | |
settings.afilter = reduce(config.attributeFilter, function (a, b) { | |
a[b] = true; | |
return a; | |
}, {}); | |
watched.push({ | |
tar: $target, | |
fn: createMutationSearcher($target, settings) | |
}); | |
// reconnect if not connected | |
if (!this._timeout) startMutationChecker(this); | |
}, | |
/** | |
* Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once | |
* @expose | |
* @return {Array.<MutationRecord>} | |
*/ | |
takeRecords: function () { | |
var mutations = [], watched = this._watched, wl = watched.length; | |
for (var i = 0; i < wl; i++) watched[i].fn(mutations); | |
return mutations; | |
}, | |
/** | |
* @expose | |
* @return undefined | |
*/ | |
disconnect: function () { | |
this._watched = []; // clear the stuff being observed | |
clearTimeout(this._timeout); // ready for garbage collection | |
/** @private */ | |
this._timeout = null; | |
} | |
}; | |
/** | |
* Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant | |
* @param {Object} data | |
* @return {Object} a MutationRecord | |
*/ | |
function MutationRecord(data) { | |
var settings = { // technically these should be on proto so hasOwnProperty will return false for non explicitly set props | |
type: null, target: null, addedNodes: [], removedNodes: [], previousSibling: null, | |
nextSibling: null, attributeName: null, attributeNamespace: null, oldValue: null | |
}; | |
for (var prop in data) | |
if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop]; | |
return settings; | |
} | |
/** | |
* Creates a func to find all the mutations | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function createMutationSearcher($target, config) { | |
/** type {Elestuct} */ | |
var $oldstate = clone($target, config); // create the cloned datastructure | |
/** | |
* consumes array of mutations we can push to | |
* | |
* @param {Array.<MutationRecord>} mutations | |
*/ | |
return function (mutations) { | |
var olen = mutations.length, dirty; | |
// Alright we check base level changes in attributes... easy | |
if (config.attr && $oldstate.attr) | |
findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter); | |
// check childlist or subtree for mutations | |
if (config.kids || config.descendents) | |
dirty = searchSubtree(mutations, $target, $oldstate, config); | |
// reclone data structure if theres changes | |
if (dirty || mutations.length !== olen) | |
/** type {Elestuct} */ | |
$oldstate = clone($target, config); | |
}; | |
} | |
/* attributes + attributeFilter helpers */ | |
/** | |
* fast helper to check to see if attributes object of an element has changed | |
* doesnt handle the textnode case | |
* | |
* @param {Array.<MutationRecord>} mutations | |
* @param {Node} $target | |
* @param {Object.<string, string>} $oldstate : Custom attribute clone data structure from clone | |
* @param {Object} filter | |
*/ | |
function findAttributeMutations(mutations, $target, $oldstate, filter) { | |
var checked = {}, attributes = $target.attributes, i = attributes.length, attr, name; | |
while (i--) { | |
attr = attributes[i]; | |
name = attr.name; | |
if (!filter || has(filter, name)) { | |
if (attr.value !== $oldstate[name]) | |
// The pushing is redundant but gzips very nicely | |
mutations.push(MutationRecord({ | |
type: 'attributes', target: $target, attributeName: name, oldValue: $oldstate[name], | |
attributeNamespace: attr.namespaceURI // in ie<8 it incorrectly will return undefined | |
})); | |
checked[name] = true; | |
} | |
} | |
for (name in $oldstate) | |
if (!(checked[name]) && $oldstate.hasOwnProperty(name)) | |
mutations.push(MutationRecord({ target: $target, type: 'attributes', attributeName: name, oldValue: $oldstate[name] })); | |
} | |
/** | |
* searchSubtree: array of mutations so far, element, element clone, bool | |
* synchronous dfs comparision of two nodes | |
* This function is applied to any observed element with childList or subtree specified | |
* Sorry this is kind of confusing as shit, tried to comment it a bit... | |
* codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func | |
* | |
* @param {Array} mutations | |
* @param {Node} $target | |
* @param {!Object} $oldstate : A custom cloned node from clone() | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function searchSubtree(mutations, $target, $oldstate, config) { | |
// Track if the tree is dirty and has to be recomputed (#14). | |
var dirty; | |
/* | |
* Helper to identify node rearrangment and stuff... | |
* There is no gaurentee that the same node will be identified for both added and removed nodes | |
* if the positions have been shuffled. | |
* conflicts array will be emptied by end of operation | |
*/ | |
function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) { | |
// the distance between the first conflicting node and the last | |
var distance = conflicts.length - 1, | |
// prevents same conflict being resolved twice consider when two nodes switch places. | |
// only one should be given a mutation event (note -~ is used as a math.ceil shorthand) | |
counter = -~((distance - numAddedNodes) / 2), $cur, oldstruct, conflict; | |
while (conflict = conflicts.pop()) { | |
$cur = $kids[conflict.i]; | |
oldstruct = $oldkids[conflict.j]; | |
// attempt to determine if there was node rearrangement... won't gaurentee all matches | |
// also handles case where added/removed nodes cause nodes to be identified as conflicts | |
if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, addedNodes: [$cur], removedNodes: [$cur], | |
// haha don't rely on this please | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
counter--; // found conflict | |
} | |
// Alright we found the resorted nodes now check for other types of mutations | |
if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// now look @ subtree | |
if (config.descendents) findMutations($cur, oldstruct); | |
} | |
} | |
/** | |
* Main worker. Finds and adds mutations if there are any | |
* @param {Node} node | |
* @param {!Object} old : A cloned data structure using internal clone | |
*/ | |
function findMutations(node, old) { | |
var $kids = node.childNodes, $oldkids = old.kids, klen = $kids.length, | |
// $oldkids will be undefined for text and comment nodes | |
olen = $oldkids ? $oldkids.length : 0; | |
// if (!olen && !klen) return; // both empty; clearly no changes | |
// we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused) | |
// map of checked element of ids to prevent registering the same conflict twice | |
var map, | |
// array of potential conflicts (ie nodes that may have been re arranged) | |
conflicts, id, // element id from getElementId helper | |
idx, // index of a moved or inserted element | |
oldstruct, | |
// current and old nodes | |
$cur, $old, | |
// track the number of added nodes so we can resolve conflicts more accurately | |
numAddedNodes = 0, | |
// iterate over both old and current child nodes at the same time | |
i = 0, j = 0; | |
// while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;) | |
while (i < klen || j < olen) { | |
// current and old nodes at the indexs | |
$cur = $kids[i]; | |
oldstruct = $oldkids[j]; | |
$old = oldstruct && oldstruct.node; | |
if ($cur === $old) { // expected case - optimized for this case | |
// check attributes as specified by config | |
if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */ findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
// check character data if node is a comment or textNode and it's being observed | |
if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// resolve conflicts; it will be undefined if there are no conflicts - otherwise an array | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
// recurse on next level of children. Avoids the recursive call when there are no children left to iterate | |
if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct); | |
i++; | |
j++; | |
} else { // (uncommon case) lookahead until they are the same again or the end of children | |
dirty = true; | |
if (!map) { // delayed initalization (big perf benefit) | |
map = {}; | |
conflicts = []; | |
} | |
if ($cur) { | |
// check id is in the location map otherwise do a indexOf search | |
if (!(map[id = getElementId($cur)])) { // to prevent double checking | |
// mark id as found | |
map[id] = true; | |
// custom indexOf using comparitor checking oldkids[i].node === $cur | |
if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, | |
addedNodes: [$cur], // $cur is a new node | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
numAddedNodes++; | |
} | |
else conflicts.push({ i: i, j: idx }); // add conflict | |
} | |
i++; | |
} | |
if ($old && | |
// special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case | |
$old !== $kids[i] | |
) { | |
if (!(map[id = getElementId($old)])) { | |
map[id] = true; | |
if ((idx = indexOf($kids, $old, i)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: old.node, removedNodes: [$old], | |
nextSibling: $oldkids[j + 1], // praise no indexoutofbounds exception | |
previousSibling: $oldkids[j - 1] | |
})); | |
numAddedNodes--; | |
} | |
else conflicts.push({ i: idx, j: j }); | |
} | |
j++; | |
} | |
}// end uncommon case | |
}// end loop | |
// resolve any remaining conflicts | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
} | |
findMutations($target, $oldstate); | |
return dirty; | |
} | |
/** | |
* Utility | |
* Clones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012 | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
* @return {!Object} : Cloned data structure | |
*/ | |
function clone($target, config) { | |
var recurse = true; // set true so childList we'll always check the first level | |
return (function copy($target) { | |
var elestruct = {/** @type {Node} */ node: $target }; | |
// Store current character data of target text or comment node if the config requests | |
// those properties to be observed. | |
if (config.charData && ($target.nodeType === 3 || $target.nodeType === 8)) | |
elestruct.charData = $target.nodeValue; | |
// its either a element, comment, doc frag or document node | |
else { | |
// Add attr only if subtree is specified or top level and avoid if | |
// attributes is a document object (#13). | |
if (config.attr && recurse && $target.nodeType === 1) | |
/** | |
* clone live attribute list to an object structure {name: val} | |
* @type {Object.<string, string>} | |
*/ | |
elestruct.attr = reduce($target.attributes, function (memo, attr) { | |
if (!config.afilter || config.afilter[attr.name]) | |
memo[attr.name] = attr.value; | |
return memo; | |
}, {}); | |
// whether we should iterate the children of $target node | |
if (recurse && ((config.kids || config.charData) || (config.attr && config.descendents))) | |
/** @type {Array.<!Object>} : Array of custom clone */ | |
elestruct.kids = map($target.childNodes, copy); | |
recurse = config.descendents; | |
} | |
return elestruct; | |
}($target)); | |
} | |
/** | |
* indexOf an element in a collection of custom nodes | |
* | |
* @param {NodeList} set | |
* @param {!Object} $node : A custom cloned node | |
* @param {number} idx : index to start the loop | |
* @return {number} | |
*/ | |
function indexOfCustomNode(set, $node, idx) { | |
return indexOf(set, $node, idx, JSCompiler_renameProperty('node')); | |
} | |
// using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like <li></li> | |
var counter = 1, // don't use 0 as id (falsy) | |
/** @const */ | |
expando = 'mo_id'; | |
/** | |
* Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern | |
* | |
* @param {Node} $ele | |
* @return {(string|number)} | |
*/ | |
function getElementId($ele) { | |
try { | |
return $ele.id || ($ele[expando] = $ele[expando] || counter++); | |
} catch (o_O) { // ie <8 will throw if you set an unknown property on a text node | |
try { | |
return $ele.nodeValue; // naive | |
} catch (shitie) { // when text node is removed: https://gist.github.com/megawac/8355978 :( | |
return counter++; | |
} | |
} | |
} | |
/** | |
* **map** Apply a mapping function to each item of a set | |
* @param {Array|NodeList} set | |
* @param {Function} iterator | |
*/ | |
function map(set, iterator) { | |
var results = [], sl = set.length; | |
for (var index = 0; index < sl; index++) | |
results[index] = iterator(set[index], index, set); | |
return results; | |
} | |
/** | |
* **Reduce** builds up a single result from a list of values | |
* @param {Array|NodeList|NamedNodeMap} set | |
* @param {Function} iterator | |
* @param {*} [memo] Initial value of the memo. | |
*/ | |
function reduce(set, iterator, memo) { | |
var sl = set.length; | |
for (var index = 0; index < sl; index++) | |
memo = iterator(memo, set[index], index, set); | |
return memo; | |
} | |
/** | |
* **indexOf** find index of item in collection. | |
* @param {Array|NodeList} set | |
* @param {Object} item | |
* @param {number} idx | |
* @param {string} [prop] Property on set item to compare to item | |
*/ | |
function indexOf(set, item, idx, prop) { | |
var sl = set.length; | |
for (/*idx = ~~idx*/; idx < sl; idx++) // start idx is always given as this is internal | |
if ((prop ? set[idx][prop] : set[idx]) === item) return idx; | |
return -1; | |
} | |
/** | |
* @param {Object} obj | |
* @param {(string|number)} prop | |
* @return {boolean} | |
*/ | |
function has(obj, prop) { | |
return obj[prop] !== undefined; // will be nicely inlined by gcc | |
} | |
// GCC hack see http://stackoverflow.com/a/23202438/1517919 | |
function JSCompiler_renameProperty(a) { | |
return a; | |
} | |
return MutationObserver; | |
}()); | |
} | |
//////////////// | |
// https://draeton.github.io/javascript/library/2011/09/11/check-if-image-exists-javascript.html | |
{ | |
var checkImageErrors = {}; | |
function checkImage(url, success, failure) { | |
var img = new Image(), // the | |
loaded = false, | |
errored = false; | |
img.onload = function () { | |
if (loaded) | |
return; | |
loaded = true; | |
if (success && success.call) | |
success.call(img); | |
}; | |
img.onerror = function () { | |
if (errored) { | |
return; | |
} | |
checkImageErrors[url] = errored = true; | |
if (failure && failure.call) { | |
failure.call(img); | |
} | |
}; | |
if (checkImageErrors[url]) { | |
img.onerror.call(img); | |
return; | |
} | |
img.src = url; | |
if (img.complete) { | |
img.onload.call(img); | |
} | |
} | |
} | |
//////////////// | |
///////////////////// | |
// my code | |
///////////////////// | |
function makeImgBig() { | |
// make more space on the site | |
jQuery(".site").css("max-width", "1920px"); | |
jQuery(".entry-content").css("max-width", "1920px"); | |
jQuery("#masthead").css("max-width", "1920px"); // search bar | |
// image align center | |
jQuery( | |
"article .entry-content p:first-of-type img:first-of-type" | |
).removeClass(); | |
// align torrentInfo stats images | |
jQuery(".entry-content ul li img:not(.wplp-lazy)").addClass("aligncenter"); | |
//text align center | |
jQuery("article").css("text-align", "center"); | |
// display to contents text is under image and not blocked by anything | |
jQuery("article .entry-content p:first-of-type").css("display", "contents"); | |
document | |
.querySelectorAll("article .entry-content h3:not(:first-of-type)+p img") //screenshots | |
.forEach((element) => { | |
if (element.flag != 1) { | |
// preview images | |
element.width *= 2.5; | |
element.height *= 2.5; | |
var imageUrl = element.src.replace(/(.*)\.240p\.jpg$/, "$1"); | |
var imageUrlAlt = element.src.replace(/(.*)\.240p\.jpg$/, "$1.1080p.jpg"); | |
checkImage(imageUrl, () => { element.src = imageUrl; }, () => { element.src = imageUrlAlt; }); | |
element.flag = 1; | |
} | |
document | |
.querySelectorAll("article .entry-content p:first-of-type img") //cover images | |
.forEach((element) => { | |
if (element.flag != 1) { | |
// cover images | |
element.width *= 2; | |
element.height *= 2; | |
} | |
element.flag = 1; | |
}); | |
}); | |
} | |
function doTheTwoColumnCss(what) { | |
jQuery(what).css({ | |
'float': 'left', | |
'width': '30%', | |
"text-align": "left", | |
"padding-left": "10%", | |
"padding-right": "10%" | |
}); | |
// make image with torrent stats not center aligned | |
jQuery(what).find("img").removeClass("aligncenter") | |
} | |
function makeArticleTwoColumns(myArticle) { | |
// COLUM 1 | |
let myDiv2 = document.createElement('div'); | |
// create div after title | |
jQuery(jQuery(myArticle).children()[1]).before(myDiv2); | |
// move everything until mirrors into the new div | |
jQuery(myDiv2).append(jQuery(jQuery(myArticle).children()[2])) | |
//apply css to make it 2 columns | |
doTheTwoColumnCss(myDiv2); | |
////////////////// | |
// COLUM 2 | |
// create div before Download Mirrors heading | |
let myDiv1 = document.createElement('div'); | |
jQuery(jQuery(myArticle).children()[3]).before(myDiv1); | |
// move all elements until screenshots heading into that div | |
for (let i = 0; i < 3; i++) { | |
jQuery(myDiv1).append(jQuery(jQuery(myArticle).children()[4])); | |
} | |
//apply css to make it 2 columns | |
doTheTwoColumnCss(myDiv1); | |
////////////////// | |
//make some space before screenshots | |
jQuery(jQuery(myDiv1).siblings()[3]).css("padding-top", "40px"); | |
// and after title | |
jQuery(jQuery(myDiv1).siblings()[0]).css("padding-bottom", "40px"); | |
} | |
(function () { | |
"use strict"; | |
jQuery.noConflict(); | |
makeImgBig(); | |
jQuery("article .entry-content:not(:contains('Upcoming repacks'))").each(function () { | |
makeArticleTwoColumns(this); | |
}); | |
})(); |
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 Gmail no Hangout and all labels | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2 | |
// @description hides hangouts from sidebar and makes all labels visible | |
// @author Alistair1231 | |
// @match https://mail.google.com/mail/u/0/* | |
// @icon https://icons.duckduckgo.com/ip2/google.com.ico | |
// @grant none | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/Gmail-no-Hangout-and-all-labels.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
{/*! | |
* Shim for MutationObserver interface | |
* Author: Graeme Yeates (github.com/megawac) | |
* Repository: https://github.com/megawac/MutationObserver.js | |
* License: WTFPL V2, 2004 (wtfpl.net). | |
* Though credit and staring the repo will make me feel pretty, you can modify and redistribute as you please. | |
* Attempts to follow spec (http:// www.w3.org/TR/dom/#mutation-observers) as closely as possible for native javascript | |
* See https://github.com/WebKit/webkit/blob/master/Source/WebCore/dom/MutationObserver.cpp for current webkit source c++ implementation | |
*/ | |
/** | |
* prefix bugs: | |
- https://bugs.webkit.org/show_bug.cgi?id=85161 | |
- https://bugzilla.mozilla.org/show_bug.cgi?id=749920 | |
* Don't use WebKitMutationObserver as Safari (6.0.5-6.1) use a buggy implementation | |
*/ | |
window.MutationObserver = window.MutationObserver || window.MozMutationObserver || (function (undefined) { | |
'use strict'; | |
/** | |
* @param {function(Array.<MutationRecord>, MutationObserver)} listener | |
* @constructor | |
*/ | |
function MutationObserver(listener) { | |
/** | |
* @type {Array.<Object>} | |
* @private | |
*/ | |
this._watched = []; | |
/** @private */ | |
this._listener = listener; | |
} | |
/** | |
* Start a recursive timeout function to check all items being observed for mutations | |
* @type {MutationObserver} observer | |
* @private | |
*/ | |
function startMutationChecker(observer) { | |
(function check() { | |
var mutations = observer.takeRecords(); | |
if (mutations.length) // fire away | |
// calling the listener with context is not spec but currently consistent with FF and WebKit | |
observer._listener(mutations, observer); | |
/** @private */ | |
observer._timeout = setTimeout(check, MutationObserver._period); | |
})(); | |
} | |
/** | |
* Period to check for mutations (~32 times/sec) | |
* @type {number} | |
* @expose | |
*/ | |
MutationObserver._period = 30; /*ms+runtime*/ | |
/** | |
* Exposed API | |
* @expose | |
* @final | |
*/ | |
MutationObserver.prototype = { | |
/** | |
* see http:// dom.spec.whatwg.org/#dom-mutationobserver-observe | |
* not going to throw here but going to follow the current spec config sets | |
* @param {Node|null} $target | |
* @param {Object|null} config : MutationObserverInit configuration dictionary | |
* @expose | |
* @return undefined | |
*/ | |
observe: function ($target, config) { | |
/** | |
* Using slightly different names so closure can go ham | |
* @type {!Object} : A custom mutation config | |
*/ | |
var settings = { | |
attr: !!(config.attributes || config.attributeFilter || config.attributeOldValue), | |
// some browsers are strict in their implementation that config.subtree and childList must be set together. We don't care - spec doesn't specify | |
kids: !!config.childList, descendents: !!config.subtree, | |
charData: !!(config.characterData || config.characterDataOldValue) | |
}, watched = this._watched; | |
// remove already observed target element from pool | |
for (var i = 0; i < watched.length; i++) | |
if (watched[i].tar === $target) watched.splice(i, 1); | |
if (config.attributeFilter) | |
/** | |
* converts to a {key: true} dict for faster lookup | |
* @type {Object.<String,Boolean>} | |
*/ | |
settings.afilter = reduce(config.attributeFilter, function (a, b) { | |
a[b] = true; | |
return a; | |
}, {}); | |
watched.push({ | |
tar: $target, | |
fn: createMutationSearcher($target, settings) | |
}); | |
// reconnect if not connected | |
if (!this._timeout) startMutationChecker(this); | |
}, | |
/** | |
* Finds mutations since last check and empties the "record queue" i.e. mutations will only be found once | |
* @expose | |
* @return {Array.<MutationRecord>} | |
*/ | |
takeRecords: function () { | |
var mutations = [], watched = this._watched, wl = watched.length; | |
for (var i = 0; i < wl; i++) watched[i].fn(mutations); | |
return mutations; | |
}, | |
/** | |
* @expose | |
* @return undefined | |
*/ | |
disconnect: function () { | |
this._watched = []; // clear the stuff being observed | |
clearTimeout(this._timeout); // ready for garbage collection | |
/** @private */ | |
this._timeout = null; | |
} | |
}; | |
/** | |
* Simple MutationRecord pseudoclass. No longer exposing as its not fully compliant | |
* @param {Object} data | |
* @return {Object} a MutationRecord | |
*/ | |
function MutationRecord(data) { | |
var settings = { // technically these should be on proto so hasOwnProperty will return false for non explicitly set props | |
type: null, target: null, addedNodes: [], removedNodes: [], previousSibling: null, | |
nextSibling: null, attributeName: null, attributeNamespace: null, oldValue: null | |
}; | |
for (var prop in data) | |
if (has(settings, prop) && data[prop] !== undefined) settings[prop] = data[prop]; | |
return settings; | |
} | |
/** | |
* Creates a func to find all the mutations | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function createMutationSearcher($target, config) { | |
/** type {Elestuct} */ | |
var $oldstate = clone($target, config); // create the cloned datastructure | |
/** | |
* consumes array of mutations we can push to | |
* | |
* @param {Array.<MutationRecord>} mutations | |
*/ | |
return function (mutations) { | |
var olen = mutations.length, dirty; | |
// Alright we check base level changes in attributes... easy | |
if (config.attr && $oldstate.attr) | |
findAttributeMutations(mutations, $target, $oldstate.attr, config.afilter); | |
// check childlist or subtree for mutations | |
if (config.kids || config.descendents) | |
dirty = searchSubtree(mutations, $target, $oldstate, config); | |
// reclone data structure if theres changes | |
if (dirty || mutations.length !== olen) | |
/** type {Elestuct} */ | |
$oldstate = clone($target, config); | |
}; | |
} | |
/* attributes + attributeFilter helpers */ | |
/** | |
* fast helper to check to see if attributes object of an element has changed | |
* doesnt handle the textnode case | |
* | |
* @param {Array.<MutationRecord>} mutations | |
* @param {Node} $target | |
* @param {Object.<string, string>} $oldstate : Custom attribute clone data structure from clone | |
* @param {Object} filter | |
*/ | |
function findAttributeMutations(mutations, $target, $oldstate, filter) { | |
var checked = {}, attributes = $target.attributes, i = attributes.length, attr, name; | |
while (i--) { | |
attr = attributes[i]; | |
name = attr.name; | |
if (!filter || has(filter, name)) { | |
if (attr.value !== $oldstate[name]) | |
// The pushing is redundant but gzips very nicely | |
mutations.push(MutationRecord({ | |
type: 'attributes', target: $target, attributeName: name, oldValue: $oldstate[name], | |
attributeNamespace: attr.namespaceURI // in ie<8 it incorrectly will return undefined | |
})); | |
checked[name] = true; | |
} | |
} | |
for (name in $oldstate) | |
if (!(checked[name]) && $oldstate.hasOwnProperty(name)) | |
mutations.push(MutationRecord({ target: $target, type: 'attributes', attributeName: name, oldValue: $oldstate[name] })); | |
} | |
/** | |
* searchSubtree: array of mutations so far, element, element clone, bool | |
* synchronous dfs comparision of two nodes | |
* This function is applied to any observed element with childList or subtree specified | |
* Sorry this is kind of confusing as shit, tried to comment it a bit... | |
* codereview.stackexchange.com/questions/38351 discussion of an earlier version of this func | |
* | |
* @param {Array} mutations | |
* @param {Node} $target | |
* @param {!Object} $oldstate : A custom cloned node from clone() | |
* @param {!Object} config : A custom mutation config | |
*/ | |
function searchSubtree(mutations, $target, $oldstate, config) { | |
// Track if the tree is dirty and has to be recomputed (#14). | |
var dirty; | |
/* | |
* Helper to identify node rearrangment and stuff... | |
* There is no gaurentee that the same node will be identified for both added and removed nodes | |
* if the positions have been shuffled. | |
* conflicts array will be emptied by end of operation | |
*/ | |
function resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes) { | |
// the distance between the first conflicting node and the last | |
var distance = conflicts.length - 1, | |
// prevents same conflict being resolved twice consider when two nodes switch places. | |
// only one should be given a mutation event (note -~ is used as a math.ceil shorthand) | |
counter = -~((distance - numAddedNodes) / 2), $cur, oldstruct, conflict; | |
while (conflict = conflicts.pop()) { | |
$cur = $kids[conflict.i]; | |
oldstruct = $oldkids[conflict.j]; | |
// attempt to determine if there was node rearrangement... won't gaurentee all matches | |
// also handles case where added/removed nodes cause nodes to be identified as conflicts | |
if (config.kids && counter && Math.abs(conflict.i - conflict.j) >= distance) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, addedNodes: [$cur], removedNodes: [$cur], | |
// haha don't rely on this please | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
counter--; // found conflict | |
} | |
// Alright we found the resorted nodes now check for other types of mutations | |
if (config.attr && oldstruct.attr) findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
if (config.charData && $cur.nodeType === 3 && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// now look @ subtree | |
if (config.descendents) findMutations($cur, oldstruct); | |
} | |
} | |
/** | |
* Main worker. Finds and adds mutations if there are any | |
* @param {Node} node | |
* @param {!Object} old : A cloned data structure using internal clone | |
*/ | |
function findMutations(node, old) { | |
var $kids = node.childNodes, $oldkids = old.kids, klen = $kids.length, | |
// $oldkids will be undefined for text and comment nodes | |
olen = $oldkids ? $oldkids.length : 0; | |
// if (!olen && !klen) return; // both empty; clearly no changes | |
// we delay the intialization of these for marginal performance in the expected case (actually quite signficant on large subtrees when these would be otherwise unused) | |
// map of checked element of ids to prevent registering the same conflict twice | |
var map, | |
// array of potential conflicts (ie nodes that may have been re arranged) | |
conflicts, id, // element id from getElementId helper | |
idx, // index of a moved or inserted element | |
oldstruct, | |
// current and old nodes | |
$cur, $old, | |
// track the number of added nodes so we can resolve conflicts more accurately | |
numAddedNodes = 0, | |
// iterate over both old and current child nodes at the same time | |
i = 0, j = 0; | |
// while there is still anything left in $kids or $oldkids (same as i < $kids.length || j < $oldkids.length;) | |
while (i < klen || j < olen) { | |
// current and old nodes at the indexs | |
$cur = $kids[i]; | |
oldstruct = $oldkids[j]; | |
$old = oldstruct && oldstruct.node; | |
if ($cur === $old) { // expected case - optimized for this case | |
// check attributes as specified by config | |
if (config.attr && oldstruct.attr) /* oldstruct.attr instead of textnode check */ findAttributeMutations(mutations, $cur, oldstruct.attr, config.afilter); | |
// check character data if node is a comment or textNode and it's being observed | |
if (config.charData && oldstruct.charData !== undefined && $cur.nodeValue !== oldstruct.charData) | |
mutations.push(MutationRecord({ type: 'characterData', target: $cur })); | |
// resolve conflicts; it will be undefined if there are no conflicts - otherwise an array | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
// recurse on next level of children. Avoids the recursive call when there are no children left to iterate | |
if (config.descendents && ($cur.childNodes.length || oldstruct.kids && oldstruct.kids.length)) findMutations($cur, oldstruct); | |
i++; | |
j++; | |
} else { // (uncommon case) lookahead until they are the same again or the end of children | |
dirty = true; | |
if (!map) { // delayed initalization (big perf benefit) | |
map = {}; | |
conflicts = []; | |
} | |
if ($cur) { | |
// check id is in the location map otherwise do a indexOf search | |
if (!(map[id = getElementId($cur)])) { // to prevent double checking | |
// mark id as found | |
map[id] = true; | |
// custom indexOf using comparitor checking oldkids[i].node === $cur | |
if ((idx = indexOfCustomNode($oldkids, $cur, j)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: node, | |
addedNodes: [$cur], // $cur is a new node | |
nextSibling: $cur.nextSibling, previousSibling: $cur.previousSibling | |
})); | |
numAddedNodes++; | |
} | |
else conflicts.push({ i: i, j: idx }); // add conflict | |
} | |
i++; | |
} | |
if ($old && | |
// special case: the changes may have been resolved: i and j appear congurent so we can continue using the expected case | |
$old !== $kids[i] | |
) { | |
if (!(map[id = getElementId($old)])) { | |
map[id] = true; | |
if ((idx = indexOf($kids, $old, i)) === -1) | |
if (config.kids) { | |
mutations.push(MutationRecord({ | |
type: 'childList', target: old.node, removedNodes: [$old], | |
nextSibling: $oldkids[j + 1], // praise no indexoutofbounds exception | |
previousSibling: $oldkids[j - 1] | |
})); | |
numAddedNodes--; | |
} | |
else conflicts.push({ i: idx, j: j }); | |
} | |
j++; | |
} | |
}// end uncommon case | |
}// end loop | |
// resolve any remaining conflicts | |
if (conflicts) resolveConflicts(conflicts, node, $kids, $oldkids, numAddedNodes); | |
} | |
findMutations($target, $oldstate); | |
return dirty; | |
} | |
/** | |
* Utility | |
* Clones a element into a custom data structure designed for comparision. https://gist.github.com/megawac/8201012 | |
* | |
* @param {Node} $target | |
* @param {!Object} config : A custom mutation config | |
* @return {!Object} : Cloned data structure | |
*/ | |
function clone($target, config) { | |
var recurse = true; // set true so childList we'll always check the first level | |
return (function copy($target) { | |
var elestruct = {/** @type {Node} */ node: $target }; | |
// Store current character data of target text or comment node if the config requests | |
// those properties to be observed. | |
if (config.charData && ($target.nodeType === 3 || $target.nodeType === 8)) | |
elestruct.charData = $target.nodeValue; | |
// its either a element, comment, doc frag or document node | |
else { | |
// Add attr only if subtree is specified or top level and avoid if | |
// attributes is a document object (#13). | |
if (config.attr && recurse && $target.nodeType === 1) | |
/** | |
* clone live attribute list to an object structure {name: val} | |
* @type {Object.<string, string>} | |
*/ | |
elestruct.attr = reduce($target.attributes, function (memo, attr) { | |
if (!config.afilter || config.afilter[attr.name]) | |
memo[attr.name] = attr.value; | |
return memo; | |
}, {}); | |
// whether we should iterate the children of $target node | |
if (recurse && ((config.kids || config.charData) || (config.attr && config.descendents))) | |
/** @type {Array.<!Object>} : Array of custom clone */ | |
elestruct.kids = map($target.childNodes, copy); | |
recurse = config.descendents; | |
} | |
return elestruct; | |
}($target)); | |
} | |
/** | |
* indexOf an element in a collection of custom nodes | |
* | |
* @param {NodeList} set | |
* @param {!Object} $node : A custom cloned node | |
* @param {number} idx : index to start the loop | |
* @return {number} | |
*/ | |
function indexOfCustomNode(set, $node, idx) { | |
return indexOf(set, $node, idx, JSCompiler_renameProperty('node')); | |
} | |
// using a non id (eg outerHTML or nodeValue) is extremely naive and will run into issues with nodes that may appear the same like <li></li> | |
var counter = 1, // don't use 0 as id (falsy) | |
/** @const */ | |
expando = 'mo_id'; | |
/** | |
* Attempt to uniquely id an element for hashing. We could optimize this for legacy browsers but it hopefully wont be called enough to be a concern | |
* | |
* @param {Node} $ele | |
* @return {(string|number)} | |
*/ | |
function getElementId($ele) { | |
try { | |
return $ele.id || ($ele[expando] = $ele[expando] || counter++); | |
} catch (o_O) { // ie <8 will throw if you set an unknown property on a text node | |
try { | |
return $ele.nodeValue; // naive | |
} catch (shitie) { // when text node is removed: https://gist.github.com/megawac/8355978 :( | |
return counter++; | |
} | |
} | |
} | |
/** | |
* **map** Apply a mapping function to each item of a set | |
* @param {Array|NodeList} set | |
* @param {Function} iterator | |
*/ | |
function map(set, iterator) { | |
var results = [], sl = set.length; | |
for (var index = 0; index < sl; index++) | |
results[index] = iterator(set[index], index, set); | |
return results; | |
} | |
/** | |
* **Reduce** builds up a single result from a list of values | |
* @param {Array|NodeList|NamedNodeMap} set | |
* @param {Function} iterator | |
* @param {*} [memo] Initial value of the memo. | |
*/ | |
function reduce(set, iterator, memo) { | |
var sl = set.length; | |
for (var index = 0; index < sl; index++) | |
memo = iterator(memo, set[index], index, set); | |
return memo; | |
} | |
/** | |
* **indexOf** find index of item in collection. | |
* @param {Array|NodeList} set | |
* @param {Object} item | |
* @param {number} idx | |
* @param {string} [prop] Property on set item to compare to item | |
*/ | |
function indexOf(set, item, idx, prop) { | |
var sl = set.length; | |
for (/*idx = ~~idx*/; idx < sl; idx++) // start idx is always given as this is internal | |
if ((prop ? set[idx][prop] : set[idx]) === item) return idx; | |
return -1; | |
} | |
/** | |
* @param {Object} obj | |
* @param {(string|number)} prop | |
* @return {boolean} | |
*/ | |
function has(obj, prop) { | |
return obj[prop] !== undefined; // will be nicely inlined by gcc | |
} | |
// GCC hack see http://stackoverflow.com/a/23202438/1517919 | |
function JSCompiler_renameProperty(a) { | |
return a; | |
} | |
return MutationObserver; | |
}()); | |
} | |
//////////////// | |
(function (window, undefined) { | |
'use strict'; | |
const jQ = jQuery; | |
jQ(document).ready(function () { | |
new MutationObserver(() => { | |
// sperator | |
jQ(jQ('div[aria-label="Hangouts"]').siblings()[1]).remove(); | |
// hangouts and meet stuff | |
jQ('div[aria-label="Hangouts"]').remove(); | |
// make the important stuff take all the space | |
jQ('div[role="navigation"]').css("height", ""); | |
// click on more | |
jQ('div[role="navigation"] span:contains("More"):not([role="button"])').click(); | |
//make sidebar thinner | |
jQuery(".aeN").each(function () { this.style.setProperty('min-width', '180px', 'important') }) | |
// make numbers appear on sidebar again | |
jQuery(".bsU").css("padding-right", "55px"); | |
}).observe(document, { subtree: true, childList: true }); | |
}); | |
})(window); |
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 igg-games/bluemediafiles auto continue after wait | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2 | |
// @description waits for cooldown and clicks continue | |
// @author Alistair1231 | |
// @match http*://bluemediafiles.com/url-generator.php?url=* | |
// @match http*://bluemediafiles.net/url-generator.php?url=* | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/iggAutoContinue.user.js | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// waiting for countown | |
var clickButton; | |
var count=0; | |
var interval = setInterval(() => | |
{ | |
// countdown = document.getElementsByClassName("item")[0].children[0].innerHTML; | |
clickButton = document.getElementById("nut").src; | |
count++; | |
console.log("Waited "+count+" seconds"); | |
console.log("image is: "+clickButton); | |
if(clickButton!==""){ | |
//clicking | |
document.getElementsByClassName("item")[0].nextElementSibling.submit(); | |
clearInterval(interval); | |
} | |
}, 1000); | |
})(); |
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 IMDB bigger thumbnails/images/poster on chart pages | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.3 | |
// @description edits image url to get the full size picture and increases poster size | |
// @author Alistair1231 | |
// @match https://www.imdb.com/chart* | |
// @icon https://www.google.com/s2/favicons?domain=imdb.com | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/imdbBigCharts.user.js | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
function makeMods(x, late) { | |
if (x.flag == null) | |
x.flag = 0; | |
if (late == false) { | |
if (x.flag != 2) { | |
try { | |
// let path = window.location.pathname.split('/'); | |
// // if on search page | |
// if(path[1]=="find") | |
let scale = 140 / x.width; | |
x.width *= scale; | |
x.height *= scale; | |
if (x.height >= 208) | |
x.height = 208; | |
// crop instead of stretch | |
x.setAttribute("style", "object-fit: cover;"); | |
let match = x.src.match(/https:\/\/m\.media-amazon\.com\/images\/[MS]\/[^\.]+\._V\d_/); | |
if (match != null) | |
x.src = match[0] + ".jpg"; | |
// x.src = x.src.match(/https:\/\/m\.media-amazon\.com\/images\/[MS]\/[^\.]+/)[0] + ".UY220_CR160,220_AL_.jpg"; | |
x.flag++; | |
} catch (e) { } | |
} | |
} | |
else if (late == true) { | |
try { | |
let scale = 80 / x.width; | |
x.width *= scale; | |
x.height *= scale; | |
// crop instead of stretch | |
x.setAttribute("style", "object-fit: cover;"); | |
let match = x.src.match(/https:\/\/m\.media-amazon\.com\/images\/[MS]\/[^\.]+\._V\d_/); | |
if (match != null) | |
x.src = match[0] + ".jpg"; | |
} catch (e) { } | |
} | |
} | |
function run() { | |
// for sites like popular movies | |
// https://www.imdb.com/chart/moviemeter/ | |
Array.from(document.querySelectorAll(".posterColumn a img")).map(x => makeMods(x, false)); | |
// for sites like search | |
// https://www.imdb.com/find?q=invin | |
Array.from(document.querySelectorAll(".primary_photo a img")).map(x => makeMods(x, false)); | |
// actor images | |
Array.from(document.querySelectorAll(".loadlate")).map(x => makeMods(x, true)); | |
setTimeout(run, 2000); | |
} | |
(function () { | |
run(); | |
})(); |
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 is.gd auto pronouncable | |
// @namespace https://github.com/Alistair1231/ | |
// @version 3 | |
// @description auto selects 'lowercase pronouncable' | |
// @author Alistair1231 | |
// @match https://is.gd/ | |
// @match https://is.gd/create.php | |
// @match https://is.gd/index.php | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/isgd.user.js | |
// @grant none | |
// @license GPL-3.0 | |
// @copyright 2020, Alistair1231 (https://openuserjs.org/users/Alistair1231) | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
// click more options (technically not necessary) | |
document.getElementById("shorturllabel").children[0].click(); | |
// select lower-case pronouncable | |
document.getElementById("options").children[4].checked=true; | |
var page = window.location.pathname.split('/')[1]; | |
// if on create.php highlight shorted url | |
if(page === "create.php"){ | |
document.getElementById("short_url").select(); | |
} | |
// If on main page highlight long url input | |
else if(page == "index.php" || page === ""){ | |
document.getElementById("urlboxcontainer").children[0].select(); | |
} | |
})(); |
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 jQuery everywhere | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2.2 | |
// @description injects jquery if not exists | |
// @author Alistair1231 | |
// @match *://*/* | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/jQuery-everywhere.user.js | |
// @grant GM_xmlhttpRequest | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
if(typeof jQuery=='undefined') { | |
// https://stackoverflow.com/questions/54499985/how-can-i-load-an-external-script-on-a-webpage-using-tampermonkey | |
GM_xmlhttpRequest({ | |
method : "GET", | |
// from other domain than the @match one (.org / .com): | |
url : "https://code.jquery.com/jquery-3.6.0.min.js", | |
onload : (ev) => | |
{ | |
let e = document.createElement('script'); | |
e.innerText = ev.responseText; | |
document.head.appendChild(e); | |
} | |
}); | |
} | |
})(); |
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 MAL bigger images | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.3 | |
// @description bigger thumbnails on MAL | |
// @author Alistair1231 | |
// @match https://myanimelist.net/* | |
// @icon https://icons.duckduckgo.com/ip2/myanimelist.net.ico | |
// @grant none | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/mal-bigger-thumbnails.user.js | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function () { | |
"use strict"; | |
setInterval(() => { | |
jQuery(document).ready( | |
jQuery("#content table .picSurround img").each(bigger) | |
); | |
jQuery(document).ready( | |
jQuery("#content table .ranking-list img").each(bigger) | |
); | |
// make animelist/mangalist images bigger | |
var checkExist = setInterval(function () { | |
//first element in list | |
if (location.href.split("/")[3] == "animelist") { | |
if ( | |
$( | |
"#list-container > div.list-block > div > table > tbody:nth-child(2) > tr.list-table-data > td.data.title.clearfix > a" | |
).length | |
) { | |
jQuery(document).ready( | |
jQuery(".list-table-data .data.image img").each(bigger) | |
); | |
clearInterval(checkExist); | |
} | |
} | |
if (location.href.split("/")[3] == "mangalist") { | |
if ( | |
$( | |
"#list-container > div.list-block > div > table > tbody:nth-child(2) > tr.list-table-data > td.data.image > a" | |
).length | |
) { | |
jQuery(document).ready( | |
jQuery(".list-table-data .data.image img").each(bigger) | |
); | |
clearInterval(checkExist); | |
} | |
} | |
}, 100); // check every 100ms | |
}, 500); | |
function bigger() { | |
var el = $(this)[0]; | |
var imgTemp = el.src.match(/(\/images\/\w+\/\d+\/\d+)(?=t?\.\w{3,4})/); | |
if (imgTemp != null) { | |
var img = "https://cdn.myanimelist.net" + imgTemp[0] + ".jpg"; | |
// el.src = el.src.replace(/https:\/\/cdn\.myanimelist\.net\/r\/\d+x\d+(\/images\/anime\/\d+\/\d+).*$/g,"https://cdn.myanimelist.net/$1.jpg") | |
if (img.match("/anime") != null || img.match("/manga") != null) { | |
el.height = 252; | |
el.width = 180; | |
jQuery(el).attr("srcset", img); | |
jQuery(el).css("object-fit", "contain"); | |
// jQuery(el).attr('src',img) | |
// jQuery(el).attr('data-srcset',img) | |
// jQuery(el).attr('data-src',img) | |
if ( | |
location.href.split("/")[3] == "animelist" || | |
location.href.split("/")[3] == "mangalist" | |
) | |
biggerList(); | |
} | |
} | |
} | |
function biggerList() { | |
jQuery(".list-table .list-table-data .data.image .image").css( | |
"height", | |
"252" | |
); | |
jQuery(".list-table .list-table-data .data.image .image").css( | |
"width", | |
"180" | |
); | |
} | |
})(); |
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 MAM search on Goodreads | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.7.5 | |
// @description Add "Search Goodreads" button to MAM | |
// @author Alistair1231 | |
// @include https://www.myanonamouse.net/t/* | |
// @grant none | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/mam.user.js | |
// ==/UserScript== | |
// Thanks for https://greasyfork.org/en/users/78880-slengpung for the inspiration | |
// https://greasyfork.org/en/scripts/24678-goodreads-plus | |
var page = window.location.pathname.split('/')[1]; | |
if(page === 't'){ | |
var bookTitle = document.getElementsByClassName("TorrentTitle")[0].innerHTML.trim(); | |
var author = document.getElementsByClassName("torDetRight torAuthors")[0].textContent; | |
// this new regex matches names like 'A B Name', they have to be changed to 'AB Name' | |
// https://regex101.com/r/MtDzfo/1 for more info on how it works | |
var regex = /(\s|^)(.*\s)(\w)\s(\w)(\s.*)/gm; | |
author = author.replace(regex,"$1$2$3$4$5"); | |
// thanks for @GardenShade for letting me know these symbols break names. I couldn't find an example so it wasn't tested. | |
bookTitle = bookTitle.replace('%', '').replace("'", '%27'); | |
var mamSearchUrl = "https://www.goodreads.com/search?q=" + bookTitle + " " + author; | |
// var dereferedUrl = "http://www.dereferer.org/?"+encodeURIComponent(mamSearchUrl); | |
// var dereferedUrl = "http://de-ref.com/?"+mamSearchUrl; | |
// var dereferedUrl = "https://url.rw/?"+encodeURIComponent(mamSearchUrl); | |
var dereferedUrl = "https://r.mrd.ninja/"+encodeURIComponent(mamSearchUrl); | |
// Add 'Search MAM' button | |
var buttonUl = document.getElementById("fInfo").childNodes; | |
var mamButton = document.createElement("div"); | |
mamButton.innerHTML = '<div id="size" class="torDetInnerCon ">'+ | |
'<div class="torDetInnerTop ">Goodreads </div>'+ | |
'<div class="torDetInnerBottomSpan "><span>'+ | |
'<a id="mamLink" href="' + dereferedUrl + '" target="_blank" class="buttonBar"><input type="button" value="Search Goodreads" /></a>'+ | |
'</span></div>'; | |
buttonUl[0].appendChild(mamButton); | |
} |
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 Remove ad/link entries from marktplaats | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2 | |
// @description Remove ad/link entries from marktplaats! | |
// @author Alistair1231 | |
// @match https://www.marktplaats.nl/q/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=marktplaats.nl | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/marktplaats.user.js | |
// @license GPLv3 | |
// @grant none | |
// ==/UserScript== | |
function removeStuff(){ | |
// enties with links to websites | |
document.querySelectorAll("span.mp-Listing-seller-link").forEach(x => x.parentElement.parentElement.remove()) | |
// ad entries at bottom | |
document.querySelector("div.mp-Listings__admarktTitle + ul").remove(); | |
// entry heading | |
document.querySelector(".mp-adsense-header.mp-text-meta").remove(); | |
// text beneath ad heading | |
document.querySelector("div.mp-Listings__admarktTitle").remove(); | |
} | |
(function() { | |
'use strict'; | |
setInterval(removeStuff,500); | |
})(); |
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 Pastebin auto select Unlisted | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1 | |
// @description auto selects unlisted when making a paste | |
// @author Alistair1231 | |
// @include https://pastebin.com/edit/* | |
// @include https://pastebin.com/clone/* | |
// @include https://pastebin.com/ | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/pastebinUnlisted.user.js | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
document.getElementById("postform-status").value=1; | |
document.getElementById("select2-postform-status-container").innerHTML="Unlisted"; | |
// Your code here... | |
})(); |
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 Path of Exile Trade always fuzzy search (tilde) | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2.1 | |
// @description always use fuzzy search, waits for active input bar and puts ~ (tilde) at the front | |
// @author Alistair1231 | |
// @match https://www.pathofexile.com/trade* | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/poeSearch.user.js | |
// @icon https://www.google.com/s2/favicons?domain=pathofexile.com | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
setInterval(() => { | |
let searchbox = document.querySelectorAll(".multiselect--active .multiselect__input"); | |
Array.from(searchbox).map(x => { | |
if ((x != null) && (x.value.match(/^~.*$/)==null)) | |
x.value= "~"+x.value; | |
}) | |
}, 1000); | |
})(); |
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 progresswww grade colors and look different | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1 | |
// @description progress now shows colorful grades | |
// @author Alistair1231 | |
// @match https://progresswww.nl/fontys/resultaten/overzicht.asp* | |
// @icon https://icons.duckduckgo.com/ip2/progresswww.nl.ico | |
// @grant none | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/progresswww-grade-colors-and-look-different.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
function colorLines() { | |
jQuery("div.prg-box__content table tbody tr:has(td:not(.seperator))").each((i, x) => { | |
var columnNo = 4; | |
if (location.href == "https://progresswww.nl/fontys/resultaten/overzicht.asp?ov=1") { | |
columnNo = 5; | |
} | |
//$(x).css({ 'background-color': '#2e3030' }) | |
jQuery("td:nth-of-type(" + columnNo + ")", x).each((j, y) => { | |
if (y.innerText < 5.5 && y.innerText != "") { | |
jQuery(y).css({ 'background-color': '#990000', 'color': '#ffffff' }); | |
//console.log(y.innerText); | |
} | |
else if (y.innerText >= 5.5 || y.innerText == "PA") { | |
jQuery(y).css({ 'background-color': '#009900', 'color': '#ffffff' }); | |
} | |
// else { | |
// jQuery(y).css('background-color', '#eaf0f4'); //eaf0f4 | |
// } | |
}); | |
}); | |
} | |
function colorRest() { | |
$(".table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th").css({ 'border-color': '#2e3030' }) | |
$('#wrapper').css({"background-color": "#303031","box-shadow": "0 0 0 1px #2e3030"}); | |
$(".page-title-box").css({"background": "#333"}); | |
$("body ").css({"color": "#dbdde0"}); | |
} | |
// eaf0f4 // 2e3030 | |
// f0f4f8 // 303031 | |
colorLines(); | |
})(); |
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 Radio.net space for toggle play/pause | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.1.1 | |
// @description Makes it so spacebar toggles pause/play instead of scrolling down the page. | |
// @author Alistair1231 | |
// @match https://www.radio.net/s/* | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/radionetSpacePause.user.js | |
// @icon https://icons.duckduckgo.com/ip2/radio.net.ico | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
function togglePlayingState(e){ | |
if(e.keyCode==32){ | |
e.preventDefault(); | |
let playButton = document.querySelector(".player__button.player__button--stopped.icon-play-circle") | |
let stopButton = document.querySelector(".player__button.player__button--playing.icon-play-circle") | |
let currentlyPlaying= playButton.style["display"]=='none' // play button hidden | |
if(currentlyPlaying){ | |
console.log("stop") | |
stopButton.click() | |
} | |
else{ | |
console.log("start") | |
playButton.click() | |
} | |
} | |
} | |
document.addEventListener('keydown', togglePlayingState, false); | |
})(); |
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 real-debrid torrents: textbox with all links | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.2 | |
// @description adds a button which when pressed creates a textbox with all links for you to copy in jDownloader2 | |
// @author Alistair1231 | |
// @match https://real-debrid.com/torrents | |
// @icon https://icons.duckduckgo.com/ip2/real-debrid.com.ico | |
// @grant none | |
// @require https://code.jquery.com/jquery-3.6.0.min.js | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/real-debrid-torrents-textbox-with-all-links.user.js | |
// @license GPL-3.0 | |
// ==/UserScript== | |
(function () { | |
var linkButton = document.createElement("input"); | |
linkButton.type = "button"; | |
linkButton.value = "Show Links"; | |
linkButton.onclick = function () { | |
createTextArea(); | |
} | |
// align right | |
jQuery(linkButton).css("float", "inline-end"); | |
// make vertically centered | |
jQuery(linkButton).css("margin-top", "10px"); | |
jQuery(".content_separator_mini")[1].append(linkButton); | |
function createTextArea() { | |
var textbox = document.createElement("textarea"); | |
jQuery(textbox).css({ "position": "fixed", "width": "80%", "height": "80%", "z-index": "999998", "background": "rgba(0,0,0,0.7)", "color": "#fff", "font-size": "16px", "font-family": "Consolas", "padding": "10px", "resize": "none", "outline": "none", "border": "none", "box-shadow": "0 0 10px #fff", "-webkit-box-shadow": "0 0 10px #fff", "-moz-box-shadow": "0 0 10px #fff", "-o-box-shadow": "0 0 10px #fff", "left": "10%", "top": "8%" }); | |
// get all the links | |
var links = jQuery.makeArray(jQuery("tr form[action='./downloader'] textarea")).map(e => e.value); | |
var names = jQuery.makeArray(jQuery("tbody td.t-left span")).map(x => x.innerText); | |
names.forEach((x, i) => { | |
links[i] = links[i] + "#name=" + x; | |
console.log(links[i]); | |
}); | |
// add the links to the textbox | |
textbox.value = links.join('\n'); | |
document.getElementsByTagName("body")[0].prepend(textbox); | |
// highlight the text in the textbox | |
textbox.select(); | |
//create close button in top right corner | |
var close = document.createElement("div"); | |
jQuery(close).css({ "position": "fixed", "top": "10%", "right": "10%", "width": "30px", "height": "30px", "background": "#fff", "border-radius": "50%", "cursor": "pointer", "text-align": "center", "line-height": "30px", "font-size": "25px", "font-weight": "bold", "color": "#000", "z-index": "999999" }); | |
close.innerHTML = "X"; | |
//when button clicked remove elements | |
jQuery(close).click(function () { | |
jQuery(textbox).remove(); | |
jQuery(close).remove(); | |
}); | |
// remove elements when escape is pressed | |
jQuery(document).keyup(function (e) { | |
if (e.keyCode == 27) { | |
jQuery(textbox).remove(); | |
jQuery(close).remove(); | |
} | |
}); | |
//remove elements when clicked outside of them | |
jQuery(document).click(function (e) { | |
if (e.target != textbox && e.target != close && e.target != linkButton) { | |
jQuery(textbox).remove(); | |
jQuery(close).remove(); | |
} | |
}); | |
document.getElementsByTagName("body")[0].prepend(close); | |
} | |
})(); |
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 TRAKT.TV: YouTube trailer search and RARBG/Torrentleech link | |
// @namespace https://greasyfork.org/en/users/12725-alistair1231 | |
// @version 0.8 | |
// @description adds a RARBG and a Torrentleech link to the link sidebar and a youtube trailer search behind the trailer button | |
// @author Alistair1231 | |
// @downloadURL https://gist.github.com/Auncaughbove17/1efc6138988425c938e6289736ada85d/raw/traktAddons.user.js | |
// @match https://trakt.tv/* | |
// @icon https://www.google.com/s2/favicons?domain=trakt.tv | |
// @grant none | |
// @license GPL-3.0 | |
// ==/UserScript== | |
function waitForSiteToLoad() { | |
let value = document.querySelectorAll(".sidebar.affixable.affix .external a"); | |
if (value == null) { | |
setTimeout(waitForSiteToLoad, 300); | |
return; | |
} | |
return value; | |
} | |
function injectRarbgButton(path, imdbButton) { | |
console.log("injecting rarbg button"); | |
let imdbId = imdbButton.href.match(/tt\d+/)[0]; | |
let rarbgButton = document.createElement("a"); | |
rarbgButton.target = "_blank"; | |
// rarbgButton.innerHTML = "RARBG"; | |
rarbgButton.innerHTML = "<img width=16 height=16 alt=\"RARBG\" src=\"https://icons.duckduckgo.com/ip2/rarbg.to.ico\">"; | |
rarbgButton.id = "rarbgButton"; | |
if (path == "shows") | |
rarbgButton.href = `https://rarbg.to/tv/${imdbId}/`; | |
else if (path == "movies") | |
rarbgButton.href = `https://rarbg.to/torrents.php?imdb=${imdbId}`; | |
imdbButton.after(rarbgButton); | |
} | |
function injectTorrentleechButton(title, rarbgButton,path) { | |
let torrentleechButton = document.createElement("a"); | |
torrentleechButton.target = "_blank"; | |
torrentleechButton.innerHTML = "<img width=16 height=16 alt=\"TL\" src=\"https://icons.duckduckgo.com/ip2/torrentleech.org.ico\">"; | |
torrentleechButton.id = "torrentleechButton"; | |
if(path == "shows") | |
torrentleechButton.href = `https://www.torrentleech.org/torrents/browse/index/categories/27/query/${title}/orderby/seeders/order/desc`; | |
if(path == "movies") | |
torrentleechButton.href = `https://www.torrentleech.org/torrents/browse/index/categories/8,37,43,14,12,13,47,27/query/${title}/orderby/seeders/order/desc`; | |
rarbgButton.after(torrentleechButton); | |
} | |
function injectYoutubeSearchButton(title) { | |
//create button for youtube search | |
let newLink = document.createElement("a"); | |
newLink.className = "popup-video one-liner trailer"; | |
newLink.target = "_blank"; | |
newLink.href = `https://www.youtube.com/results?search_query=%22${title}%22+trailer`; | |
// copied from other button (for text and icon) | |
newLink.innerHTML += '<div class="icon"><div class="fa fa-youtube-play"></div></div><div class="text"><div class="site">Trailer Search</div></div>'; | |
newLink.id = "youtubeSearchButton"; | |
//put new button after old, if not already there | |
let oldTrailer = document.querySelector(".popup-video.one-liner.trailer"); | |
oldTrailer.after(newLink); | |
} | |
function run() { | |
let path = window.location.pathname.split('/'); | |
let linkArray = document.querySelectorAll(".sidebar.affixable.affix .external a"); | |
linkArray = waitForSiteToLoad(); | |
try { | |
let title; | |
if(window.location.pathname.split('/')[3]==null) // if on main page of tv-show | |
title = document.querySelector(".mobile-title h1").firstChild.textContent.replace(/ $/g,""); // gets title and removes space at the end | |
else // on page like /seasons/1 | |
title = document.querySelector(".mobile-title h2 a").innerHTML.replace(/: $/g,""); // gets title and removes ': ' from the end | |
let urlTitle=encodeURIComponent(title); | |
let imdbButton = Array.from(linkArray).filter(x => x.innerHTML == "IMDB")[0]; | |
if (document.getElementById("rarbgButton") == null) // if rarbg button doesn't exist | |
injectRarbgButton(path[1], imdbButton); | |
if ((document.querySelector("a.trailer")!=null) && (document.getElementById("youtubeSearchButton")==null)) // if there is a trailer button but no trailer search was added | |
injectYoutubeSearchButton(urlTitle); | |
if ((document.getElementById("torrentleechButton") == null) && (document.getElementById("rarbgButton") != null)) // if torrentleech button doesn't and rarbg button does exist | |
injectTorrentleechButton(urlTitle, rarbgButton,path[1]); | |
} catch (err) { } | |
} | |
(function () { | |
'use strict'; | |
setInterval(run, 700); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment