├── scripts ├── CompleteROMs.com.js ├── NewGrounds.com - My Friend Pedro.js ├── Yuzu Game Compatibility Sorter.js ├── WebHackery - MutationObserver.js ├── RPS Adblock Blocker Blocker.js ├── Reddit NSFW Saved Post Scrubber.js ├── Fast GitHub Repo Delete.js └── Napalm FTP Indexer.js └── README.md /scripts/CompleteROMs.com.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name completeroms.com 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.1 5 | // @description try to take over the world! 6 | // @author You 7 | // @match *://*.completeroms.com/* 8 | // @run-at document-end 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | var jQuery = window.jQuery 13 | 14 | //-- Always show download button 15 | jQuery('.download-button').removeAttr('style') 16 | 17 | //-- Remove countdown text and bottom alert 18 | jQuery('.margin-bottom-30, .alert-danger').remove() 19 | 20 | //-- Clean top spacing 21 | jQuery('.text-center').toggleClass('margin-top-50 padding-top-30') 22 | 23 | //-- Removes iframes 24 | setInterval(function(){ jQuery('iframe').remove() }, 100); 25 | 26 | //-- Remove pop-up behavior 27 | window.K200 = undefined 28 | -------------------------------------------------------------------------------- /scripts/NewGrounds.com - My Friend Pedro.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name NewGrounds - Pedro 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.1 5 | // @description Custom "My Friend Pedro" page on NewGrounds. 6 | // @author You 7 | // @match https://www.newgrounds.com/portal/view/641215 8 | // @run-at document-end 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | //-- Get rid of jQuery warnings in Tampermonkey (Thanks for the idea, FreeER!) 13 | var jQuery = window.jQuery 14 | 15 | //-- Modify header of game container: 16 | //-- Change rating to 'M', center it with game title, and remove right-hand div 17 | var podHead = jQuery('.pod-head') 18 | podHead.children('.rated-t').attr('class', 'rated-m').css('text-align','center') 19 | podHead.children('div').remove() 20 | 21 | //-- Grab main container that game is in, set new customized CSS for it, then store in variable myFriendPedro via clone() 22 | var myFriendPedro = jQuery('.maincontent-wide').css({ 23 | 'width': '635px', 24 | 'margin': '0', 25 | 'position': 'absolute', 26 | 'top': '50%', 27 | 'left': '50%', 28 | 'transform': 'translate(-50%, -50%)' 29 | }).clone() 30 | 31 | //-- Apply background image to body, delete all elements within body, then append custom cloned game container 32 | jQuery('body').css({ 33 | 'background-image': 'url("https://cdn3.dualshockers.com/wp-content/uploads/2018/06/My-Friend-Pedro-Key-Art.png")', 34 | 'background-size': 'cover' 35 | }).empty().append(myFriendPedro) 36 | -------------------------------------------------------------------------------- /scripts/Yuzu Game Compatibility Sorter.js: -------------------------------------------------------------------------------- 1 | // Webpage this script is for: https://yuzu-emu.org/game/ 2 | // 3 | // Description: This script allows you to sort games by compatibility type. 4 | // 5 | // Use: Click on the page header ("Game Compatibility List") to reset the games list, 6 | // or click on one of the 7 compatiblity types (Perfect, Great, Okay, etc.) in the list 7 | // up top to show only games of that compatibility type. 8 | // 9 | // Note: Either toss this script in a Tampermonkey script so it'll automatically run every 10 | // time you load the page, or paste it all into your browser's DevTools console and then 11 | // press Enter to execute the code! 12 | 13 | // Get all rows of games from the game table 14 | const allGames = [...document.querySelectorAll('[data-key]')]; 15 | 16 | // Get all rows from the "Game Compatibility List" table 17 | const gameCompatList = [...document.querySelector('table > tbody').children]; 18 | 19 | // Resets games list or sorts games list by chosen compatibility type 20 | function sort(data) { 21 | for (game of allGames) { 22 | const compatibility = parseInt(game.childNodes[3].getAttribute('data-compatibility')); 23 | 24 | if (data === 'reset' || data === compatibility) { 25 | game.style.display = 'table-row'; 26 | } else { 27 | game.style.display = 'none'; 28 | } 29 | } 30 | } 31 | 32 | // IIFE to nix ads 33 | (function noAds() { 34 | // Get rid of ads column 35 | document.querySelector('.columns').lastElementChild.remove(); 36 | 37 | // Correct games column width 38 | document.querySelector('.columns > .column').classList.remove('is-two-thirds'); 39 | })(); 40 | 41 | // When clicking on a compatibility list row, sort games by that compatibility type 42 | gameCompatList.forEach((compat, idx) => { 43 | compat.addEventListener('click', function() { 44 | idx === gameCompatList.length - 1 ? sort(99) : sort(idx); 45 | }); 46 | }); 47 | 48 | // Clicking on page title resets game list to original, unsorted state 49 | document.querySelector('.title').addEventListener('click', () => { 50 | sort('reset'); 51 | }); 52 | -------------------------------------------------------------------------------- /scripts/WebHackery - MutationObserver.js: -------------------------------------------------------------------------------- 1 | // Instagram Signup/Login and Image Re-Linker via the MutationObserver API 2 | // Video Tutorial URL: https://youtu.be/KWWGC2TbT70 3 | 4 | // FUNCTION: Checks for presence of signup footer and modal, then removes them if they're on the page. 5 | function loginCheck() { 6 | const body = document.querySelector('body'); 7 | const isHidden = body.style.overflow === 'hidden'; 8 | const hasModal = body.lastElementChild.getAttribute('role') === 'presentation' ? true : false; 9 | const footer = [...document.querySelectorAll('nav > div')].pop().firstElementChild.firstElementChild.lastElementChild.firstElementChild.firstElementChild.firstElementChild; 10 | 11 | if (footer) { 12 | footer.remove(); 13 | } 14 | 15 | if (isHidden && hasModal) { 16 | body.lastElementChild.remove(); 17 | body.style.overflow = 'visible'; 18 | 19 | loginObserver.disconnect(); 20 | } 21 | } 22 | 23 | // FUNCTION: Adds full-sized image link to each thumbnail's hyperlink. 24 | function reLink() { 25 | const linkList = document.querySelectorAll('a'); 26 | 27 | linkList.forEach((link) => { 28 | const linkAttribute = link.getAttribute('href'); 29 | 30 | if (linkAttribute.startsWith('/p/')) { 31 | const linkFormatted = 'https://instagram.com' + linkAttribute + 'media/?size=l' 32 | 33 | link.setAttribute('href', linkFormatted); 34 | 35 | // Log to the console the thumbnail and respective link for hover/click. 36 | console.log('-=-=-=-=-=-=-'); 37 | console.log('Image: ', link.firstElementChild); 38 | console.log('Direct Link: ', linkFormatted); 39 | }; 40 | }); 41 | } 42 | 43 | // FUNCTION: Callback function for MutationObserver which runs when changes are observed. 44 | // Note: Beware of lexical scope with arrow functions, like in the forEach below. 45 | // For example, if you need 'this' to reference the local scope of the loop, then use 46 | // a traditional 'for', 'for...of', or 'for...in' loop. 47 | function mutationsCallback(mutations) { 48 | mutations.forEach((mutation) => { 49 | if (mutation.type === 'childList') { 50 | reLink(); 51 | } else if (mutation.type === 'attributes') { 52 | loginCheck(); 53 | } 54 | }); 55 | } 56 | 57 | // Node(s)/element(s) to be observed. 58 | const imgNode = [...document.querySelectorAll('main > div > div')].pop().lastElementChild.firstElementChild.firstElementChild; 59 | const body = document.querySelector('body'); 60 | 61 | // Create a new MutationObserver instance and pass the callback function to it. 62 | // Then call the observe() method and pass it the node to be observed, as well as 63 | // the type(s) of mutation(s) to watch for. 64 | const imgObserver = new MutationObserver(mutationsCallback); 65 | imgObserver.observe(imgNode, { childList: true }); 66 | 67 | // Same stuff as above, but for our login observer. 68 | const loginObserver = new MutationObserver(mutationsCallback); 69 | loginObserver.observe(body, { attributes: true }); -------------------------------------------------------------------------------- /scripts/RPS Adblock Blocker Blocker.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name RockPaperShotgun Adblock Blocker Blocker 3 | // @namespace http://rockpapershotgun.com/ 4 | // @version 0.1 5 | // @description Remove ad-block roadblock from rockpapershotgun.com 6 | // @author You 7 | // @match *://*.rockpapershotgun.com/* 8 | // @grant none 9 | // ==/UserScript== 10 | 11 | //----------------------------- 12 | //-- jQuery version of the hack 13 | //----------------------------- 14 | 15 | //-- Remove Tampermonkey warnings about jQuery 16 | /* let $ = window.$; 17 | 18 | //-- Function to run after setTimeout time completes 19 | function doStuffs() { 20 | //-- Remove roadblock divs 21 | $('body > div').eq(-1).remove(); 22 | $('body > div').eq(-1).remove(); 23 | 24 | //-- Remove overflow-y hidden on body and html 25 | $('html, body').css('overflow-y', 'visible'); 26 | 27 | //-- Remove .leaderboards div 28 | $('.leaderboards').remove(); 29 | 30 | //-- Remove padding-right used for sidebar ads 31 | $('.ads-enabled .page>main .above').css('padding-right', '0'); 32 | } 33 | 34 | //-- Run function 1 second after page loads 35 | setTimeout(() => { doStuffs() }, 1000); */ 36 | 37 | //--------------------------------- 38 | //-- JavaScript version of the hack 39 | //--------------------------------- 40 | 41 | //-- Function to run after setTimeout time completes 42 | function doStuffs() { 43 | //-- NICE-TO-KNOW: This will hide the elements vis CSS modifications instead of removing them 44 | //-- NOTE: This doesn't guarantee to always get the last 2 divs in our scenario 45 | // document.querySelectorAll('body > div')[3].style.display = 'none'; 46 | // document.querySelectorAll('body > div')[4].style.display = 'none'; 47 | 48 | //-- NICE-TO-KNOW: Chrome's mnemonic for querySelectorAll() (returns array, not nodelist!) 49 | //-- NOTE: Works within Chrome console only, not from within a script like this 50 | // $$('body > div').slice(-1)[0].remove(); 51 | // $$('home > div').slice(-1)[0].remove(); 52 | 53 | //-- NICE-TO-KNOW: Pre-ES6 way to convert nodelist to array (can then use array methods) 54 | // [].slice.call(document.querySelectorAll('body > div')).slice(-1)[0].remove(); 55 | // [].slice.call(document.querySelectorAll('body > div')).slice(-1)[0].remove(); 56 | 57 | //-- ES6 spread operator to convert nodelist to array 58 | [...document.querySelectorAll('body > div')].slice(-1)[0].remove(); 59 | [...document.querySelectorAll('body > div')].slice(-1)[0].remove(); 60 | 61 | //-- Set overflow-y to visible on html and body 62 | document.querySelector('html').style.overflowY = "visible"; 63 | document.querySelector('body').style.overflowY = "visible"; 64 | 65 | //-- Remove padding-right used for sidebar ads 66 | document.querySelector('.ads-enabled .page > main .above').style.paddingRight = "0"; 67 | 68 | //-- Remove .leaderboards div 69 | document.querySelector('.leaderboards').remove(); 70 | } 71 | 72 | //-- Run function 1 second after page loads 73 | setTimeout(() => { doStuffs() }, 1000); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript, jQuery, and Tampermonkey Scripts 2 | These are various scripts I've written for personal use, demonstration purposes (i.e. via my YouTube channel), friends, etc. Brief descriptions for each can be found below. 3 | 4 | **[RPS Adblock Blocker Blocker.js](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/RPS%20Adblock%20Blocker%20Blocker.js)** - ***(JavaScript / jQuery / Tampermonkey)*** | This script is from my video tutorial, "[WebHackery Ep. 1: Let's Defeat an Adblock Blocker!](https://youtu.be/gCV8INwY-sc)", where I demonstrate how to defeat an ad-blocking roadblock from a website! I first prototype the hack in jQuery, then convert it to vanilla JavaScript, and finally set everything up in a Tampermonkey script. 5 | 6 | **[Fast GitHub Repo Delete.js](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/Fast%20GitHub%20Repo%20Delete.js)** - ***(JavaScript)*** | A work-in-progress script that currently adds a delete button to a user's GitHub repositories main page, then fast-deletes any given repo after its delete button has been clicked 5 times! Great for use via Tampermonkey, or can be ran from the console while on the repositories page. 7 | 8 | **[Napalm FTP Indexer.js](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/Napalm%20FTP%20Indexer.js)** - ***(jQuery / Tampermonkey)*** | This is an extensive script that modifies searchftps.net to do a number of things, including remove ads, make requests to the server with hash information to obtain links with which I repurpose download buttons on search results pages, and more! 9 | 10 | **[CompleteROMs.com.js](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/CompleteROMs.com.js)** - ***(jQuery / Tampermonkey)*** | Modifies completeroms.com to remove tricky iframes and ads. Also finds download functionality and overrides time-related enabled/disabled status. This script was used in [a YouTube video of mine](https://www.youtube.com/watch?v=Vxpm_wrCm7M) to teach viewers about fun ways to use Chrome DevTools, jQuery, and Tampermonkey! 11 | 12 | **[NewGrounds.com - My Friend Pedro.js](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/NewGrounds.com%20-%20My%20Friend%20Pedro.js)** - ***(jQuery / Tampermonkey)*** | Modifies the "My Friend Pedro" game page on NewGrounds. This script was used in [a YouTube video of mine](https://www.youtube.com/watch?v=S18ciaTi4oA) to teach viewers more about using Chrome DevTools, jQuery, and Tampermonkey to hack around with a site! 13 | 14 | **[Reddit NSFW Saved Post Scrubber](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/Reddit%20NSFW%20Saved%20Post%20Scrubber.js)** - ***(jQuery)*** | Gets all saved posts and populates them on one page, then unsaves all saved NSFW posts. One thing to be fixed is that the script currently runs synchronously, so the browser will hang until the script is completed. 15 | 16 | **[WebHackery Ep. 3 - Instagram Hacks via the MutationObserver API](https://github.com/dsasmblr/JavaScript-jQuery-and-Tampermonkey/blob/master/scripts/WebHackery%20-%20MutationObserver.js)** - ***(JavaScript)*** | Gets rid of Instagram's forced login/signup roadblocks, and hyperlinks every thumbnail image to the largest available resolution of the image. Finally, code persistence is achieved via using the MutationObserver API. This script was created/used [in episode 3 of WebHackery](https://youtu.be/KWWGC2TbT70), my web development/hacking series on YouTube! 17 | 18 | 19 | -------------------------------------------------------------------------------- /scripts/Reddit NSFW Saved Post Scrubber.js: -------------------------------------------------------------------------------- 1 | /* Reddit NSFW Saved Post Scrubber - Instructions 2 | 3 | Note: Before running this script, you should know two particular side effects. First, 4 | this script unsaves ALL saves marked with the NSFW stamp. That includes subs like 5 | /r/wtf of which you may not want to unsave posts from. In that regard, this script 6 | is an all-or-none thing. 7 | 8 | Second, there are plenty of risque subreddits that aren't stamped NSFW or 18+. As 9 | such, those saves will remain; however, after a first run of the script, you should 10 | be able to more quickly scan through your remaining saved posts and manually 11 | finish the job. 12 | 13 | Now onward to the instructions! 14 | 15 | 1. While logged into your account, go to the following URL after you first replace 16 | YourUsernameHere with your actual username: 17 | 18 | https://www.reddit.com/user/YourUsernameHere/saved/ 19 | 20 | 2. Click anywhere in this script now and press CTRL + A, which will highlight 21 | everything. Then, press CTRL + C to copy it all. 22 | 23 | 3. Click on the tab you have Reddit opened in from step one. Press F12 and you 24 | will see the DevTools section appear. In its bottom pane, you will see a > 25 | character. Click it and you should now see a cursor slowly flashing beside it. 26 | 27 | 4. Press CTRL + V, which will paste what you copied of this script. Now press Enter. 28 | The script will run and you can watch everything happen in the console as URLs 29 | are logged. Once it says, "That's all, folks!", everything will be completed. 30 | Simply refresh the page and all the NSFW-tagged saved posts will be removed. 31 | 32 | */ 33 | 34 | //-- fullUrl keeps track of the URLs scraped from the "Next" button on the page. 35 | let fullUrl = document.location.href; 36 | 37 | //-- This function scrapes data from AJAX results and places them on the page. 38 | function modifyPage(data, status) { 39 | 40 | //-- Find the main container of saved posts, then strip its id so there 41 | //-- aren't duplicates of it when appending to main #siteTable container 42 | let container = jQuery(data).find('#siteTable').attr('id', ''); 43 | 44 | //-- If true is passed, append container. Else, append final container, clean 45 | //-- up nav buttons, then simulate click on "unsave" of each saved NSFW post. 46 | if (status) { 47 | jQuery("#siteTable").append(container); 48 | } else { 49 | jQuery("#siteTable").append(container); 50 | jQuery('.nav-buttons').hide(); 51 | jQuery('.nsfw-stamp').parent().siblings('.save-button').find('a').click(); 52 | console.log("That's all, folks!"); 53 | } 54 | } 55 | 56 | //-- While fullUrl isn't false, run AJAX calls synchronously. 57 | while (fullUrl) { 58 | jQuery.ajax(fullUrl, { 59 | type: 'GET', 60 | dataType: 'html', 61 | async: false, 62 | success: function(data) { 63 | try { 64 | //-- Set fullUrl to the href value of the .next-button element 65 | fullUrl = jQuery(data).find('.next-button')[0].childNodes[0].href; 66 | } 67 | catch { 68 | //-- Set fullUrl to false; finalizes AJAX calls and ends while-loop 69 | fullUrl = false; 70 | } 71 | 72 | //-- If fullUrl is set to false, wrap things up with a final call to modifyPage(). 73 | //-- Else, keep adding AJAX data containers to main container. 74 | //-- The 'count=25' check keeps the first page from being duplicated to itself. 75 | if (!fullUrl) { 76 | modifyPage(data, false); 77 | } else { 78 | if (!fullUrl.includes('count=25')) { 79 | modifyPage(data, true); 80 | } 81 | console.log(fullUrl); 82 | } 83 | } 84 | }); 85 | } -------------------------------------------------------------------------------- /scripts/Fast GitHub Repo Delete.js: -------------------------------------------------------------------------------- 1 | /*-- 2 | Set up global variables ------ 3 | --*/ 4 | 5 | //-- Used for button creation 6 | let repoNames = document.querySelectorAll("[itemprop='name codeRepository']"); 7 | let starBtns = document.querySelectorAll("[aria-label='Star this repository']"); 8 | 9 | //-- Used for multiple user/repo references throughout 10 | let userName = document.querySelector(".user-profile-link strong").innerText; 11 | 12 | //-- Used to keep track of loop iterations, and for index referencing 13 | let arrayCount = 0; 14 | 15 | //-- Keeps track of total consecutive mouse clicks needed on repo delete buttons 16 | let clickObj = { 17 | "repoName": "", 18 | "clicks": 0 19 | }; 20 | 21 | /*-- 22 | Set up functions ------ 23 | --*/ 24 | 25 | //-- FUNC: Deletes the repo 26 | function deleteRepo(text) { 27 | //-- Build form from settings page 28 | let formStart = text.indexOf(`