Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save varenc/1fe600021346edcd562e7e715317ac19 to your computer and use it in GitHub Desktop.
Save varenc/1fe600021346edcd562e7e715317ac19 to your computer and use it in GitHub Desktop.
Force energy saver mode or tab memory discarding on Google Chrome on macOS
#### Force energy saver mode or tab memory discarding on Google Chrome on macOS
# Works even when you're plugged into AC power and not on battery or when your battery or memory is not low.
# The script below works by just automating clicks on the chrome://discards page which allows you to force these behaviors
#
# Setup instructions:
# - Just add the functions below to your .zshrc, .bashrc, or any other shell config file
# - Or save them to a file and add `source <path-to-file>` to a shell rc
# - You must also have Chrome "Allow JavaScript from Apple Events" enabled. This is the Chrome menu: View -> Developer -> Allow JavaScript from Apple Events
# - You must also grant macOS accessibility permissions but you should be prompted for this on first run.
#
# After installed:
# - `chromeDiscardMemory` proctively discards ALL chrome tab memory
# - `chromeToggleEnergySaver` toggles Chrome energy saver mode
# - You can also setup automators like Alfred or Apple Shortcuts to run these functions
function chromeDiscardMemory() {
# click all of the enabled "Proactive Discard" buttons in Chrome to free up memory
__chromeDiscardHelper "deepQuerySelectorAll(document,'div[is=\"action-link\"]:not([disabled])').forEach((el,n) => { if (el.innerText.indexOf(\"Proactive Discard\") > -1) { el.click() } })" "All Chrome tabs have been discarded";
}
function chromeToggleEnergySaver() {
# click the toggle battery saver mode button in Chrome
__chromeDiscardHelper "deepQuerySelectorAll(document,'div[is=\"action-link\"]').find(element => /toggle.*battery\\\s+saver/i.test(element.textContent)).click()" "Chrome energy saver mode toggled";
# the selector 'deepQuerySelectorAll(document,"#discards > div:nth-child(2)")[0].click()' is cleaner and also works but it seems more brittle
}
# This is the shared helper function that does the actual work of navigating to the chrome://discards page,
# defining the deepQuerySelectorAll function, and running the passed in JS code which just clicks the appropriate buttons
function __chromeDiscardHelper() {
[ $#@ -ne 2 ] && echo "Usage: $0 <JS CODE> <success-message>" >&2 && return 1;
/usr/bin/osascript -l JavaScript <<EndOfScript
ObjC.import("stdlib");
const chrome = Application("Google Chrome");
const activeTab = chrome.windows[0].activeTab;
let navigatedToDiscards = false;
if (activeTab.url() !== "chrome://discards/") {
activeTab.url = "chrome://discards/";
navigatedToDiscards = true;
delay(0.5);
}
// The below is a bit confusing due to multiple layers of embedding/escaping.
activeTab.execute({ javascript: \`
// deepQuerySelectorAll is just like querySelectorAll but it also searches shadow roots recursively
// This is necessary for the chrome://discards page which makes extensive use of shadow roots
// confession: GPT-4 wrote deepQuerySelectorAll for me...
function deepQuerySelectorAll(root = document, selector) {
const results = Array.from(root.querySelectorAll(selector));
root.querySelectorAll("*").forEach(el => {
if (el.shadowRoot) {
results.push(...deepQuerySelectorAll(el.shadowRoot, selector));
}
});
return results;
}
$1 ; // this first argument, the JS code executed in Chrome
alert("${2}");
\`});
// return to the previous page iff we weren't already on the chrome://discards page
if (navigatedToDiscards) {
console.log("Pausing and then telling Chrome to go back to previous page");
delay(1);
activeTab.goBack();
}
\$.exit(0);
EndOfScript
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment