Skip to content

Instantly share code, notes, and snippets.

@gsuberland
Created May 21, 2022 19:45
Show Gist options
  • Save gsuberland/af8373a6add07ab7e9a2792379803369 to your computer and use it in GitHub Desktop.
Save gsuberland/af8373a6add07ab7e9a2792379803369 to your computer and use it in GitHub Desktop.
Tampermonkey / Greasemonkey script to automatically set the privacy of replies to unlisted by default on Mastodon.
// ==UserScript==
// @name Mastodon Unlisted Replies
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Sets the privacy of replies to unlisted by default on Mastodon.
// @author Graham Sutherland (@gsuberland@chaos.social)
// @match https://chaos.social/* https://mastodon.social/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=chaos.social
// @grant none
// @run-at document-idle
// ==/UserScript==
// https://stackoverflow.com/a/39165137/978756
function FindReact(dom, traverseUp = 0) {
const key = Object.keys(dom).find(key=>{
return key.startsWith("__reactFiber$") // react 17+
|| key.startsWith("__reactInternalInstance$"); // react <17
});
const domFiber = dom[key];
if (domFiber == null) return null;
// react <16
if (domFiber._currentElement) {
let compFiber = domFiber._currentElement._owner;
for (let i = 0; i < traverseUp; i++) {
compFiber = compFiber._currentElement._owner;
}
return compFiber._instance;
}
// react 16+
const GetCompFiber = fiber=>{
//return fiber._debugOwner; // this also works, but is __DEV__ only
let parentFiber = fiber.return;
while (typeof parentFiber.type == "string") {
parentFiber = parentFiber.return;
}
return parentFiber;
};
let compFiber = GetCompFiber(domFiber);
for (let i = 0; i < traverseUp; i++) {
compFiber = GetCompFiber(compFiber);
}
return compFiber.stateNode;
}
(function() {
'use strict';
document.mastodon_unlistreply = {};
document.mastodon_unlistreply.elements = {};
document.mastodon_unlistreply.react = {};
document.mastodon_unlistreply.timers = {};
// use setInterval to wait for the forms to be set up and working
document.mastodon_unlistreply.timers.elementFinder = window.setInterval(function() {
var pagers = document.getElementsByClassName('drawer__pager');
if (pagers.length == 0)
return;
var composers = pagers[0].getElementsByClassName('compose-form');
if (composers.length == 0)
return;
var privacy_dropdowns = composers[0].getElementsByClassName('privacy-dropdown');
if (privacy_dropdowns.length == 0)
return;
document.mastodon_unlistreply.elements.pager = pagers[0];
document.mastodon_unlistreply.elements.composer = composers[0];
document.mastodon_unlistreply.elements.privacy = privacy_dropdowns[0];
document.mastodon_unlistreply.react.composer = FindReact(document.mastodon_unlistreply.elements.composer);
document.mastodon_unlistreply.react.privacy = FindReact(document.mastodon_unlistreply.elements.privacy);
// ok, setup complete. kill the elementFinder timer.
clearInterval(document.mastodon_unlistreply.timers.elementFinder);
document.mastodon_unlistreply.timers.elementFinder = null;
// every 500ms we check for changes.
document.mastodon_unlistreply.timers.update = window.setInterval(function() {
let composer = document.mastodon_unlistreply.react.composer;
let privacy = document.mastodon_unlistreply.react.privacy;
// only care about replies
if (composer.props.isInReply)
{
// get the reply indicator element and component so we can see if it changed since we last touched things
document.mastodon_unlistreply.elements.reply = document.mastodon_unlistreply.elements.composer.getElementsByClassName('reply-indicator')[0];
document.mastodon_unlistreply.react.reply = FindReact(document.mastodon_unlistreply.elements.reply);
// have we touched this composer since it was last updated? (react removes extra properties on update)
if (!composer.props.hasOwnProperty('__unlistreply_touched'))
{
// there has been an update! mark as touched.
composer.props.__unlistreply_touched = new Date();
// have we touched the reply since it was last updated? (react removes extra properties on update)
let reply = document.mastodon_unlistreply.react.reply;
if (!reply.props.hasOwnProperty('__unlistreply_touched'))
{
// there has been an update! mark as touched.
reply.props.__unlistreply_touched = new Date();
// if the reply is marked as public and the control is enabled, mark the reply as unlisted.
if (privacy.props.value == 'public' && !privacy.props.disabled)
{
privacy.handleChange('unlisted');
}
}
}
}
}, 500);
}, 500);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment