Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
FirewallRemover/

# Logs
logs
*.log
Expand Down Expand Up @@ -102,4 +104,3 @@ dist

# TernJS port file
.tern-port
.vscode/settings.json
28 changes: 28 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"name": "vscode-jest-tests.v2.OhMonkey",
"request": "launch",
"args": [
"--runInBand",
"--watchAll=false",
"--testNamePattern",
"${jest.testNamePattern}",

],
"cwd": "${workspaceFolder}",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"disableOptimisticBPs": true,
"program": "${workspaceFolder}/node_modules/.bin/jest",
"windows": {
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
}
}
]
}
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"jest.runMode": "on-demand",
"jest.rootPath": ".",
"testing.automaticallyOpenPeekView": "never",
"jest.jestCommandLine": "npx jest",
"editor.trimWhitespaceOnDelete": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true
}
16 changes: 16 additions & 0 deletions Amazon/AmazonNeutralProtectionButton.user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// ==UserScript==
// @name Amazon Neutral Protection Button
// @description Remove the bright yellow background on button labeled "Add Protection" (extended warranty)
// @author https://github.com/mkazin
// @homepage https://github.com/mkazin/OhMonkey/tree/main/Amazon
// @version 0.1
// @license BSD-3-Clause
// @namespace http://tampermonkey.net/
// @match https://www.amazon.com/*/dp/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=amazon.com
// @grant GM_addStyle
// ==/UserScript==

const EITHER_BUTTON_SELECTOR = "div.attach-warranty-button-row span.a-button"

GM_addStyle(`${EITHER_BUTTON_SELECTOR} { background-color: white; border-color: black; }`)
9 changes: 9 additions & 0 deletions Amazon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Amazon.com

### [Amazon Neutral Protection Button](AmazonNeutralProtectionButton.user.js)
Removes formatting highlighting the button to buy an extended warranty.

Turns this: <img src="img/AmazonNeutralProtectionButton-1_Before.png">

Into this:
<img src="img/AmazonNeutralProtectionButton-2_After.png">


### [Amazon Variation Pricer](AmazonVariationPricer.user.js)
Shows prices on every color/size option of item.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 8 additions & 12 deletions BostonGlobe.com/Remove BostonGlobe Sports.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
// @license BSD-3-Clause
// @match http://*.bostonglobe.com/*
// @match https://www.bostonglobe.com/*
// @require https://github.com/mkazin/OhMonkey/raw/refs/tags/observer-v0.0.4/_Utils/Observer.js
// ==/UserScript==

import { ObserverTracker } from 'https://github.com/mkazin/OhMonkey/raw/refs/tags/observer-v0.0.4/_Utils/Observer.js';

const SPORTS_TERMS = ['Football', 'NFL', 'Damar Hamlin',
'Basketball', 'NBA', 'Celtics',
'Baseball', 'MLB', 'Major League', 'Sox',
Expand Down Expand Up @@ -73,19 +76,12 @@ window.cleanSportsPosts = function() {
removeMatchingElementsContainingText("h2.headline span", term, grandparentNavigator)
})
};
console.log(ObserverTracker)

// Observe changes in the page and reapply.
// Taken from Navneet Khare's fantastic "Remove Sponsored Posts" TamperMonkey script at:
// https://openuserjs.org/install/finitenessofinfinity/Remove_Sponsored_Posts.user.js
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var target = document.getElementsByTagName("body")[0];
var config = { attributes: true, childList: true, characterData: true };

var mutationObserver = new MutationObserver(function(mutations) {
cleanSportsPosts();
});

mutationObserver.observe(target, config);
async function run() {
whenElementAppears("body", cleanSportsPosts);
}
run();
cleanSportsPosts();


50 changes: 28 additions & 22 deletions Google/GoogleQuestionSuggestionRemover.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,37 @@
// @version 1.0
// @description Removes the unhelpful sections in Google suggesting worse questions to ask
// @license BSD-3-Clause
// @match https://google.com/search?*
// @match https://www.google.com/search?*
// @match https://google.com/search*
// @match https://www.google.com/search*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @run-at document-end
// @run-at document-start
// @grant GM_addStyle
// ==/UserScript==

function hideSelector(selector) {
GM_addStyle(`${selector} { display: none !important; }`)
}
function run() {
const HEADER_SELECTOR = 'div.d0fCJc.BOZ6hd'
const QUESTION_SELECTOR = 'div[jsname="yEVEwb"]'
// Note- the parent part of the selector here is common to other sections
const PEOPLE_ALSO_ASK_SELECTOR = 'div.xfX4Ac.JI5uCe.qB9BY.yWNJXb :has(div.cUnQKe)'
//const WHAT_PEOPLE_ARE_SAYING_SELECTOR = 'div.ULSxyf' // This breaks regular search results, check if :has() is a possibile solution
const LEARN_MORE_LABEL_SELECTOR = 'div.ZKfmAf'
const LEARN_MORE_BOX_SELECTOR = 'div.kLMmLc'
const AI_OVERVIEW_IMAGE_SELECTOR = 'div.oLJ4Uc.l3foLb'
//const PEOPLE_ALSO_SEARCH_FOR_SELECTOR = 'div.ULSxyf' // This breaks regular search results (and is same as above selector)

const HEADER_SELECTOR = 'div.d0fCJc.BOZ6hd'
const QUESTION_SELECTOR = 'div[jsname="yEVEwb"]'
const PEOPLE_ALSO_ASK_SELECTOR = 'div.MjjYud div.cUnQKe'
const WHAT_PEOPLE_ARE_SAYING_SELECTOR = 'div.ULSxyf'
const ALL_SELECTORS =
[
HEADER_SELECTOR
, QUESTION_SELECTOR
, PEOPLE_ALSO_ASK_SELECTOR
, WHAT_PEOPLE_ARE_SAYING_SELECTOR
]
const SELECTORS_TO_HIDE = [
HEADER_SELECTOR
, QUESTION_SELECTOR
, PEOPLE_ALSO_ASK_SELECTOR
// , WHAT_PEOPLE_ARE_SAYING_SELECTOR
Copy link

Copilot AI Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider removing the commented-out selectors if they are no longer needed, to reduce clutter and avoid potential confusion during future maintenance.

Copilot uses AI. Check for mistakes.
, LEARN_MORE_LABEL_SELECTOR
, LEARN_MORE_BOX_SELECTOR
, AI_OVERVIEW_IMAGE_SELECTOR
// , PEOPLE_ALSO_SEARCH_FOR_SELECTOR
]
GM_addStyle(`${SELECTORS_TO_HIDE.join(', ')} { display: none !important; }`)

ALL_SELECTORS.forEach(selector => hideSelector(selector))
}

run()
// Allow AI Overview to take up full width now that the "Learn More" section is hidden
const AI_OVERVIEW_CONTAINER_SELECTOR = "div.UxeQfc"
const AI_OVERVIEW_SELECTOR = "div.LT6XE"
GM_addStyle(AI_OVERVIEW_CONTAINER_SELECTOR + ' { grid-template-columns: unset; }')
GM_addStyle(AI_OVERVIEW_SELECTOR + ' { max-width: unset; }')
4 changes: 4 additions & 0 deletions Google/YoutubeHideNextVideos.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ const SELECTORS_TO_HIDE = [
"div.ytp-endscreen-content",
// "Related" panel
"div#related",
// YouTube "Playables"
// The part preceeding ~ in this selector can also get rid of both Playables and "Shorts".
// Replace everything starting with ~ to get rid of both.
"ytd-rich-section-renderer.style-scope.ytd-rich-grid-renderer:has(h2) ~ ytd-rich-section-renderer.style-scope.ytd-rich-grid-renderer:has(h2)",
]

GM_addStyle(`${SELECTORS_TO_HIDE.join(",")} { display:none; }`)
Expand Down
6 changes: 4 additions & 2 deletions Google/YoutubeNoComment.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// @name YouTube No Comment
// @namespace https://github.com/mkazin/OhMonkey
// @author Michael Kazin
// @version 1.0
// @version 1.1
// @description Hides comments to help you avoid engaging
// @license BSD-3-Clause
// @match https://*.youtube.com/*
Expand All @@ -20,10 +20,12 @@ const SELECTORS = [
"#comments #action-buttons",
// Entire comments section
"#comments",
// Chat for live streams
"#chat-container",
// Buttons on shorts videos (youtube.com/shorts/)
"div#like-button",
"div#comments-button",
]

GM_addStyle(`${SELECTORS.join(",")} { display:none; }`)
GM_addStyle(`${SELECTORS.join(", ")} { display:none; }`)

27 changes: 22 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
# OhMonkey
A collection of GreaseMonkey/TamperMonkey scripts I wrote
A collection of Userscripts I've written for my own use

## What are GreaseMonkey and TamperMonkey?
## What's a "Userscript"?
Userscripts are JavaScript programs which are run in a web browser and can modify webpage content, add new features, automate tasks, and enhance the overall user experience in ways the website owner did not provide. Take a look through my scripts to get an idea of the kind of changes I've introduced.

[GreaseMonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/) and [TamperMonkey](https://www.tampermonkey.net/) are browser extensions that serve as user script managers. They allow users to customize the behavior of websites they visit by running user scripts, which are small snippets of JavaScript code. These scripts can modify webpage content, add new features, automate tasks, and enhance the overall user experience.
A couple good examples I like to show folks:
* [*America's Test Kitchen Amazon Pricing*](AmericasTestKitchen/README.md) - Adds the current Amazon price of the kitchen products reviewed by ATK.
* [*Amazon Variation Pricer*](Amazon/README.md#amazon-variation-pricer) - displays the prices for each color variation of a product
* [*YouTube No Comment*](Google/README.md#no-comment) - hides the comment section on YouTube videos.

GreaseMonkey is the original and ran only on Mozilla Firefox. TamperMonkey was historically used on Google Chrome and other Chromium-based browsers, but has since been implemented on all browsers and is in more active development.
## What's with "Monkey"?
[GreaseMonkey](https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/), [TamperMonkey](https://www.tampermonkey.net/), and [ViolentMonkey](https://violentmonkey.github.io/) are browser extensions that serve as userscript managers. They are responsible for running the appropriate scripts when the user visits a supported website.

GreaseMonkey is the original and ran only on Mozilla Firefox. TamperMonkey was historically used on Google Chrome and other Chromium-based browsers, but has since been implemented on all browsers and is in more active development. ViolentMonkey is the newest, is open source, and supports many browsers.

Why are they called that? I never really thought much about it. "Grease Monkey" is an old slang term for an auto mechanic. Today "monkey" is a verb used by engineers to describe tinkering with technology, possibly tracing back to the original term. "Tamper" seems obvious, whereas "violent"...? Beats me.

## Ok... and "Oh Monkey"?
Other than the obvious reference to these browser extensions, it's a phrase I adopted from a colleague I worked with long ago. It was a lovely little phrase he'd often use in place of cursing or as an exclamation of surprise or excitement.

He's a guy I really enjoyed working with, learned a lot from, and still greatly admire as an engineer and human being. So I hope he doesn't mind me stealing and sharing it. Obviously, I didn't name him here out of respect for his privacy.

Anyway, I found his phrase to be both professional and fun. I started using it later jobs and it tends to get positive- if sometimes confused- reactions from the folks I've worked with since.

## Support
Feel free to create an issue to:
Expand All @@ -18,7 +33,9 @@ Feel free to create an issue to:

If you need something more complex, I might be available for hire. Check out my website for info.

Otherwise, if you like these and find them handy, let me know!
Another place you can try is the [/r/GreaseMonkey](https://www.reddit.com/r/GreaseMonkey/) subreddit. The folks there will sometimes help create a script if you ask nicely.

* Otherwise, if you like these and find them handy, please let me know! Or feel free to hit that button on the right and buy me a coffee.


## In Remembrance
Expand Down
12 changes: 12 additions & 0 deletions Reddit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Reddit Scripts

## Reddit.com main page

### [Subreddit Hider](RedditSubredditHider.user.js)
Adds a button to filter out subreddits you don't want to see.

For example, this annoying karma-farming Subreddit:

<img src="./img/SubredditHider.png">

Does not require an account or being logged in. Stores the list of hidden subreddits in your browser.
78 changes: 78 additions & 0 deletions Reddit/RedditSubredditHider.user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// ==UserScript==
// @name Reddit Subreddit Hider
// @namespace https://github.com/mkazin/OhMonkey
// @author Michael Kazin
// @version 1.0
// @description Subreddit filter
// @license BSD-3-Clause
// @match https://www.reddit.com/
// @icon https://www.google.com/s2/favicons?sz=64&domain=reddit.com
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_addStyle
// @run-at document-end
// @require https://raw.githubusercontent.com/mkazin/OhMonkey/refs/heads/main/_Utils/Observer.js
// ==/UserScript==

const POST_SELECTOR = 'shreddit-post[subreddit-name]';
const CACHE_KEY = 'rsh-subreddit-list'

async function init() {
// Hide previously saved subreddits
const subreddits = (await GM_getValue(CACHE_KEY))?.split(',') || [];
subreddits.forEach(name => hideSubreddit(name));
// console.log(`Loaded list of ${subreddits.length} hidden subreddits: ${subreddits.join(',')}`);

// Add filter button to posts on page load
document.querySelectorAll(POST_SELECTOR).forEach(postElement => {
const subredditName = postElement.getAttribute('subreddit-name');
if (!subreddits.includes(subredditName) && !postElement.querySelector('#hide-subreddit-button')) {
createFilterButton(postElement);
}
});

// Observe for new posts being added and add a filter button to each
wheneverElementAppears(
POST_SELECTOR,
(postElement) => { createFilterButton(postElement); },
document,
0,
"RedditSubredditHider"
);
}

function hideSubreddit(subredditName) {
const rule = `article:has(shreddit-post[subreddit-name="${subredditName}"]) { display: none; }`;
GM_addStyle(rule);
}

function createFilterButton(postElement) {
const newSection = document.createElement('div')
const creditBar = postElement.querySelector(`[id*="feed-post-credit-bar-"]`);
creditBar.prepend(newSection)

const newButton = document.createElement('button');
newButton.classList.add('button-primary');
newButton.id = 'hide-subreddit-button';
newButton.innerText = 'Hide Subreddit'
newButton.onclick = clickHandler;
newSection.appendChild(newButton);
}

async function clickHandler(event) {
const subreddits = (await GM_getValue(CACHE_KEY))?.split(',') || [];
const postElement = event.target.closest('shreddit-post');
const subredditName = postElement.getAttribute('subreddit-name');
if (subreddits.includes(subredditName)) {
console.warn(`Subreddit ${subredditName} is already hidden.`);
return;
}

hideSubreddit(subredditName);
subreddits.push(subredditName);
await GM_setValue(CACHE_KEY, subreddits.join(','));
// console.log(`Subreddit ${subredditName} has been hidden.`);
// console.log(`New list of hidden subreddits: ${subreddits.join(',')}`);
}

init();
Binary file added Reddit/img/SubredditHider.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading