Greasy Fork Total Downloads

Shows a user's total downloads.

目前为 2024-09-19 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name Greasy Fork Total Downloads
  3. // @namespace -
  4. // @version 1.2.1
  5. // @description Shows a user's total downloads.
  6. // @author NotYou
  7. // @match *://greasyfork.org/*/users/*
  8. // @match *://sleazyfork.org/*/users/*
  9. // @license GPL-3.0
  10. // @run-at document-body
  11. // @grant GM_xmlhttpRequest
  12. // @require https://update.greasyfork.org/scripts/445697/1244619/Greasy%20Fork%20API.js
  13. // ==/UserScript==
  14.  
  15. ~function(GreasyFork) {
  16. class Installs {
  17. static async getData(userId) {
  18. const userData = await GreasyFork.getUserData(userId)
  19.  
  20. return (userData.all_listable_scripts || userData.scripts).reduce((acc, curr) => {
  21. acc.total += curr.total_installs
  22. acc.daily += curr.daily_installs
  23.  
  24. return acc
  25. }, {
  26. total: 0,
  27. daily: 0
  28. })
  29. }
  30. }
  31.  
  32. class User {
  33. static getId(url) {
  34. const match = url.match(/https?:\/\/(greasyfork|sleazyfork)\.org\/[a-zA-Z]+(\-[a-zA-Z]+)?\/users\/(?<userId>\d+)/)
  35.  
  36. if (match) {
  37. const { userId } = match.groups
  38.  
  39. return userId
  40. } else {
  41. return '1'
  42. }
  43. }
  44.  
  45. static getLocale($languageSelectorLocale) {
  46. return $languageSelectorLocale ? $languageSelectorLocale.value || 'en-US' : 'en-US'
  47. }
  48. }
  49.  
  50. class Stat {
  51. static createItem(data, text, color) {
  52. const node = document.createElement('span')
  53. node.style.fontSize = '15px'
  54. node.style.borderRadius = '3px'
  55. node.style.backgroundColor = 'rgb(45, 45, 45)'
  56. node.style.color = 'rgb(255, 255, 255)'
  57. node.style.margin = '0 4px'
  58. node.style.padding = '0 4px'
  59. node.style.display = 'inline-flex'
  60. node.style.alignItems = 'center'
  61. node.style.gap = '4px'
  62. node.style.boxShadow = `0 0 0 2px ${color}`
  63. node.textContent = data + ' ' + text
  64.  
  65. const circle = document.createElement('span')
  66. circle.style.width = '8px'
  67. circle.style.height = '8px'
  68. circle.style.borderRadius = '50%'
  69. circle.style.background = color
  70.  
  71. node.prepend(circle)
  72.  
  73. return node
  74. }
  75. }
  76.  
  77. class Data {
  78. static async getData() {
  79. const { href } = location
  80. const $languageSelectorLocale = document.querySelector('#language-selector-locale')
  81. const userLocale = User.getLocale($languageSelectorLocale)
  82. const userId = User.getId(href)
  83. const installsData = await Installs.getData(userId)
  84.  
  85. return {
  86. userLocale,
  87. installsData
  88. }
  89. }
  90. }
  91.  
  92. class Main {
  93. static init() {
  94. window.addEventListener('DOMContentLoaded', async () => {
  95. const { userLocale, installsData } = await Data.getData()
  96. const { total, daily } = installsData
  97. const $total = Stat.createItem(total.toLocaleString(userLocale), 'Installs', 'rgb(123, 23, 23)')
  98. const $daily = Stat.createItem(daily.toLocaleString(userLocale), 'Daily Installs', 'rgb(185, 32, 32)')
  99. const $header = document.querySelector('div.sidebarred-main-content h3:first-child')
  100.  
  101. $header.appendChild($total)
  102. $header.appendChild($daily)
  103. })
  104. }
  105. }
  106.  
  107. Main.init()
  108. }(GreasyFork)
  109.  
  110.  
  111.  
  112.  
  113.  
  114.  
  115.  
  116.  
  117.  
  118.  
  119.  
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.