Greasyfork/Sleazyfork Update Checks Display

Display today's script installations, update checks, and feedback.

当前为 2024-12-08 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Greasyfork/Sleazyfork Update Checks Display
  3. // @description Display today's script installations, update checks, and feedback.
  4. // @icon https://greasyfork.org/vite/assets/blacklogo96-CxYTSM_T.png
  5. // @version 1.3
  6. // @author afkarxyz
  7. // @namespace https://github.com/afkarxyz/misc-scripts/
  8. // @supportURL https://github.com/afkarxyz/misc-scripts/issues
  9. // @license MIT
  10. // @match https://greasyfork.org/*
  11. // @match https://sleazyfork.org/*
  12. // @grant none
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17. function formatNumber(num) {
  18. return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  19. }
  20. function displayScriptStats() {
  21. document.head.appendChild(Object.assign(document.createElement('style'), {
  22. textContent: '.script-list-installs, .script-list-update-checks, .script-list-feedback { opacity: 1; }'
  23. }));
  24. function addStat(element, label, className) {
  25. const list = element.querySelector('.inline-script-stats');
  26. if (!list) return;
  27. const dt = document.createElement('dt');
  28. const dd = document.createElement('dd');
  29. dt.className = className;
  30. dd.className = className;
  31. dt.textContent = label;
  32. dd.textContent = '...';
  33. list.lastElementChild.parentNode.insertBefore(dt, list.lastElementChild.nextSibling);
  34. dt.after(dd);
  35. return dd;
  36. }
  37. document.querySelectorAll('li[data-script-id]').forEach(script => {
  38. const feedbackElement = addStat(script, 'Feedback', 'script-list-feedback');
  39. const installsElement = addStat(script, 'Installs', 'script-list-installs');
  40. const checksElement = addStat(script, 'Checks', 'script-list-update-checks');
  41. script.dataset.feedbackElement = feedbackElement.id = `feedback-${script.dataset.scriptId}`;
  42. script.dataset.installsElement = installsElement.id = `installs-${script.dataset.scriptId}`;
  43. script.dataset.checksElement = checksElement.id = `checks-${script.dataset.scriptId}`;
  44. });
  45. }
  46. const collectScriptLinks = () =>
  47. Array.from(document.querySelectorAll('li[data-script-id]'))
  48. .map(el => {
  49. const domain = window.location.hostname;
  50. const scriptId = el.getAttribute('data-script-id');
  51. const scriptName = el.getAttribute('data-script-name')
  52. .toLowerCase()
  53. .replace(/[^a-z0-9]+/g, '-');
  54. return {
  55. url: `${domain}/en/scripts/${scriptId}-${scriptName}`,
  56. element: el
  57. };
  58. });
  59. async function fetchStats(scriptInfo) {
  60. const apiUrl = `https://forksapis.vercel.app/${scriptInfo.url}`;
  61. try {
  62. const response = await fetch(apiUrl);
  63. if (!response.ok) {
  64. throw new Error('Network response was not ok');
  65. }
  66. return await response.json();
  67. } catch (error) {
  68. console.error('Error fetching stats:', error);
  69. return null;
  70. }
  71. }
  72. function updateStats(scriptInfo, stats) {
  73. if (!stats) return;
  74. const element = scriptInfo.element;
  75. const feedbackElement = document.getElementById(element.dataset.feedbackElement);
  76. const installsElement = document.getElementById(element.dataset.installsElement);
  77. const checksElement = document.getElementById(element.dataset.checksElement);
  78. if (feedbackElement) feedbackElement.textContent = formatNumber(stats.feedback);
  79. if (installsElement) installsElement.textContent = formatNumber(stats.installs);
  80. if (checksElement) checksElement.textContent = formatNumber(stats.checks);
  81. }
  82. async function init() {
  83. displayScriptStats();
  84. const scriptInfos = collectScriptLinks();
  85. console.log('Found URLs:', scriptInfos.map(info => info.url));
  86. const fetchPromises = scriptInfos.map(async (scriptInfo) => {
  87. const stats = await fetchStats(scriptInfo);
  88. updateStats(scriptInfo, stats);
  89. });
  90. await Promise.all(fetchPromises);
  91. }
  92. if (document.readyState === 'loading') {
  93. document.addEventListener('DOMContentLoaded', init);
  94. } else {
  95. init();
  96. }
  97. })();