Skip to content

Instantly share code, notes, and snippets.

@alexrintt
Last active March 8, 2023 23:31
Show Gist options
  • Save alexrintt/7775eb3fe7d6444a916e1402c1ae04c1 to your computer and use it in GitHub Desktop.
Save alexrintt/7775eb3fe7d6444a916e1402c1ae04c1 to your computer and use it in GitHub Desktop.
Tampermonkey extension that parses almost any text string in the specific format: TZ(+1) to UTC, so you can see what is the timezone of your friend living in mars,
// ==UserScript==
// @name Annotate Discord user timezones
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://discord.com/*
// @icon https://icons.duckduckgo.com/ip3/discord.com.ico
// @grant none
// ==/UserScript==
/**
* function to calculate local time
* in a different city
* given the city's UTC offset
*/
function calcTime({ offsetHours, offsetMinutes, ahead = false }) {
offsetHours = isNaN(offsetHours) ? 0 : offsetHours
offsetMinutes = isNaN(offsetMinutes) ? 0 : offsetMinutes
const dir = ahead ? 1 : -1
offsetHours = Math.abs(offsetHours) * dir
offsetMinutes = Math.abs(offsetMinutes) * dir
// create Date object for current location
var d = new Date();
// get UTC time in msec
var utc = d.getTime();
// create new Date object for different city
// using supplied offset
var nd = new Date(utc + (3600000 * offsetHours + 60000 * offsetMinutes));
// return time as a string
return [nd.getUTCHours(), nd.getUTCMinutes()];
}
(function () {
'use strict';
// because discord developers thought they could hide localStorage from the browser, see:
// https://stackoverflow.com/questions/52509440/discord-window-localstorage-is-undefined-how-to-get-access-to-the-localstorage
function getLocalStoragePropertyDescriptor() {
const iframe = document.createElement('iframe');
document.head.append(iframe);
const pd = Object.getOwnPropertyDescriptor(iframe.contentWindow, 'localStorage');
iframe.remove();
return pd;
}
// We have several options for how to use the property descriptor
// once we have it. The simplest is to just redefine it:
Object.defineProperty(window, 'localStorage', getLocalStoragePropertyDescriptor());
window.addEventListener("load", function () {
// create a new regex instance to avoid weird stuff happening.
// i am not sure what is exactly but i remember suffering with it in the past.
// and if you suck at regexes like me, use https://regexr.com/.
const baseRegex = () => /.*TZ\((\+|-)?([0-9][0-9]?)(:([1-5][0-9]))?\)/g
const tzRegex = () => /TZ\((\+|-)?([0-9][0-9]?)(:([1-5][0-9]))?\)/g
const hourRegex = () => /\d\d:\d\d/g
const selectors = 'tz_____selectors____discord____ext__tamp';
const STOP_TRANSVERSE = 1 << 1
function set(k, v) {
localStorage.setItem(k, JSON.stringify(v))
}
function remove(k) {
localStorage.removeItem(k)
}
function get(k) {
return JSON.parse(localStorage.getItem(k) || "[]")
}
function looper() {
console.log("Updating your friend timezones...")
for (const selector of get(selectors)) {
try {
applyTzConversion("." + selector.split(" ").join("."))
} catch(e) {
console.log("Error: " + e)
set(selectors, get(selectors).filter(e => e !== selector))
}
}
setTimeout(looper, 1 * 1000)
}
function applyTzConversion(selector) {
const elements = [...document.querySelectorAll(selector)]
for (const element of elements) {
transverse(element, function (node) {
if (hasMatch(node.textContent) && node.children.length === 0) {
const [fullmatch, tz, h, colon, m] = [...node.textContent.matchAll(baseRegex())][0]
const ahead = !tz || tz === "+"
const offsetHours = Number(h)
const offsetMinutes = Number(m)
const [hours, minutes] = calcTime({ ahead, offsetHours, offsetMinutes })
if(hourRegex().test(node.textContent)) {
node.textContent = node.textContent.replace(hourRegex(), `${hours.toString().padStart(2, 0)}:${minutes.toString().padStart(2, 0)}`)
} else {
node.textContent = node.textContent.replace(tzRegex(), `${hours.toString().padStart(2, 0)}:${minutes.toString().padStart(2, 0)} ${[...node.textContent.match(tzRegex())][0]}`)
}
return STOP_TRANSVERSE
}
})
}
}
function transverse(node, callback) {
if (callback(node) === STOP_TRANSVERSE) return
for (const child of node.children) {
transverse(child, callback)
}
}
function hasMatch(text) {
return baseRegex().test(text)
}
window.addEventListener("click", function (e) {
if (hasMatch(e.target.innerText)) {
set(selectors, [...new Set([...get(selectors), [...e.target.classList].join(' ')])])
}
})
setTimeout(looper, 1 * 1000);
})
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment