mightypork / MastoThrottle

// ==UserScript==
// @name         MastoThrottle
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Stops you from wasting unhealthy amounts of time on Mastodon
// @author       @MightyPork@dev.gtitch.social
// @match        https://dev.glitch.social/web/*
// @match        https://glitch.social/web/*
// @match        https://cybre.space/web/*
// @match        https://witches.town/web/*
// @match        https://mastodon.social/web/*
// @match        https://computerfairi.es/web/*
// @match        https://a.weirder.earth/web/*
// @match        https://ephemeral.glitch.social/web/*
// @grant        none
// @license      MIT
// ==/UserScript==

// # What this plugin does
// 
// After a set time, the mastodon interface will be covered by an overlay with a countdown.
// When the countdown expires, you can click the overlay to get another dosis of masto-time.
// 
// When you first open the tab, it's configurable whether to start immemdiately or show the
// expired overlay waiting for a click.
// 
// With some adjustments this could be adapted to any website.
// 
// # Limitations
// 
// - Due to cross-origin policies, it's not possible (in the form of userscript) to track all
//   your instances. This means each instance gets its own throttle timer. It works best when 
//   you have one primary instance where you go exclusively.
// 
// - The unlocked time runs even if you close the tab. Keep that in mind. Closing the tab to 
//   "keep some minutes for later" won't work.
// 
// - To make it run on your instance, add it as a new @match entry at the top
// 

(function() {
    'use strict';

    // ---------------- CONFIGURATION -----------------------

    /* How long to allow mastodon access */
    const OPEN_TIME_MIN = 2

    /* Duration of the lock-down period */
    const LOCKED_TIME_MIN = 15

    /* Toggle: Automatically unlock when opening mastodon after the lock time has passed
     * If 'false', the overlay will be shown waiting for a click */
    const AUTO_UNLOCK = true

    // -----------------------------------------------------

    let locked, t_opened, t_close, overlay

    const _log = (msg) => console.log('[MastoThrottle] ' + msg)

    /** Get unix timestamp */
    const time = () => Math.round(+new Date()/1000)

    /** Check if lock time elapsed and user can unlock */
    const isUnlockAllowed = () => (time() >= t_close + LOCKED_TIME_MIN*60)

    /** Unlock on request by user */
    const doUnlock = () => {
        _log("Unlocked")
        const now = time()
        t_close = now + OPEN_TIME_MIN*60
        t_opened = now;
        localStorage.setItem("mt_opentime", t_opened)
        overlay.style.display = 'none'
        locked = false
    }

    const doLock = () => {
        _log("Opening overlay")
        locked = true
        updateLockedText()
        overlay.style.display = 'flex'
    }

    const updateLockedText = () => {
        if (isUnlockAllowed()) {
            overlay.textContent = 'Click here to begin'
            overlay.style.cursor = 'pointer'
        } else {
            const remain = t_close+LOCKED_TIME_MIN*60 - time()

            let t = `${remain} s`
            if (remain > 60) {
                t = `${Math.floor(remain/60)}:${(''+(remain%60)).padStart(2, '0')}`
            }

            overlay.textContent = `429 Throttled | ${t}`
            overlay.style.cursor = 'default'
        }
    }

    /* Load settings */
    {
        const now = time()

        t_opened = localStorage.getItem("mt_opentime")
        if (t_opened === null) {
            t_opened = now
            localStorage.setItem("mt_opentime", t_opened)
        } else {
            t_opened = +t_opened
        }
        t_close = t_opened + OPEN_TIME_MIN*60

        locked = (now > t_close)

        _log(`Started, open time ${OPEN_TIME_MIN} min, lock time ${LOCKED_TIME_MIN} min`)
        _log(`Last open ${Math.round((now - t_opened) / 6) / 10} min ago`)
    }

    /* build the overlay */
    {
        overlay = document.createElement('DIV')
        overlay.style.display = 'none'
        overlay.style.fontSize = '48pt'
        overlay.style.background = 'white'
        overlay.style.position = 'absolute'
        overlay.style.left = '0'
        overlay.style.top = '0'
        overlay.style.right = '0'
        overlay.style.bottom = '0'
        overlay.style.zIndex = '999'
        overlay.style.color = '#4AA5FF'
        overlay.textContent = '429 Throttled'

        /* append to the main wrapper */
        document.getElementById('mastodon').appendChild(overlay)

        /* Handler for user unlocking by overlay click */
        overlay.addEventListener('click', () => {
            if (isUnlockAllowed()) doUnlock();
        })
    }

    /* Apply the initial lock, or auto-unlock */
    if (locked) doLock()
    if (AUTO_UNLOCK && locked && isUnlockAllowed()) {
        doUnlock();
    }

    /* Main timing loop */
    setInterval(() => {
        if (locked) {
            updateLockedText()
        }
        if (!locked && time() >= t_close) {
            doLock()
        }
    }, 1000)
})();