Last active
March 8, 2023 23:31
-
-
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,
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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