Greasy Fork Total Downloads

Shows a user's total downloads.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name Greasy Fork Total Downloads
// @namespace -
// @version 1.2.2
// @description Shows a user's total downloads.
// @author NotYou
// @match *://greasyfork.org/*/users/*
// @match *://sleazyfork.org/*/users/*
// @license GPL-3.0
// @run-at document-body
// @grant GM_xmlhttpRequest
// @require https://update.greasyfork.org/scripts/445697/1244619/Greasy%20Fork%20API.js
// ==/UserScript==

~function(GreasyFork) {
    class Installs {
        static async getData(userId) {
            const userData = await GreasyFork.getUserData(userId)

            return (userData.all_listable_scripts || userData.scripts).reduce((acc, curr) => {
                acc.total += curr.total_installs
                acc.daily += curr.daily_installs

                return acc
            }, {
                total: 0,
                daily: 0
            })
        }
    }

    class User {
        static getId(url) {
            const match = url.match(/https?:\/\/(greasyfork|sleazyfork)\.org\/[a-zA-Z]+(\-[a-zA-Z]+)?\/users\/(?<userId>\d+)/)

            if (match) {
                const { userId } = match.groups

                return userId
            } else {
                return '1'
            }
        }

        static getLocale($languageSelectorLocale) {
            return $languageSelectorLocale ? $languageSelectorLocale.value || 'en-US' : 'en-US'
        }
    }

    class Stat {
        static createItem(data, text, color) {
            const node = document.createElement('span')
            node.style.fontSize = '15px'
            node.style.borderRadius = '3px'
            node.style.backgroundColor = 'rgb(45, 45, 45)'
            node.style.color = 'rgb(255, 255, 255)'
            node.style.margin = '0 4px'
            node.style.padding = '0 4px'
            node.style.display = 'inline-flex'
            node.style.alignItems = 'center'
            node.style.gap = '4px'
            node.style.boxShadow = `0 0 0 2px ${color}`
            node.textContent = data + ' ' + text

            const circle = document.createElement('span')
            circle.style.width = '8px'
            circle.style.height = '8px'
            circle.style.borderRadius = '50%'
            circle.style.background = color

            node.prepend(circle)

            return node
        }
    }

    class Data {
        static async getData() {
            const { href } = location
            const $languageSelectorLocale = document.querySelector('#language-selector-locale')
            const userLocale = User.getLocale($languageSelectorLocale)
            const userId = User.getId(href)
            const installsData = await Installs.getData(userId)

            return {
                userLocale,
                installsData
            }
        }
    }

    class Main {
        static init() {
            window.addEventListener('DOMContentLoaded', async () => {
                const { userLocale, installsData } = await Data.getData()
                const { total, daily } = installsData
                const $total = Stat.createItem(total.toLocaleString(userLocale), total > 1 ? 'Installs' : 'Install', 'rgb(123, 23, 23)')
                const $daily = Stat.createItem(daily.toLocaleString(userLocale), daily > 1 ? 'Daily Installs' : 'Daily Install', 'rgb(185, 32, 32)')
                const $header = document.querySelector('div.sidebarred-main-content h3:first-child')

                $header.appendChild($total)
                $header.appendChild($daily)
            })
        }
    }

    Main.init()
}(GreasyFork)