Display today's script installations, update checks, and feedback.
当前为
// ==UserScript==
// @name Greasyfork/Sleazyfork Update Checks Display
// @description Display today's script installations, update checks, and feedback.
// @icon https://greasyfork.org/vite/assets/blacklogo96-CxYTSM_T.png
// @version 1.3
// @author afkarxyz
// @namespace https://github.com/afkarxyz/misc-scripts/
// @supportURL https://github.com/afkarxyz/misc-scripts/issues
// @license MIT
// @match https://greasyfork.org/*
// @match https://sleazyfork.org/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
function formatNumber(num) {
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function displayScriptStats() {
document.head.appendChild(Object.assign(document.createElement('style'), {
textContent: '.script-list-installs, .script-list-update-checks, .script-list-feedback { opacity: 1; }'
}));
function addStat(element, label, className) {
const list = element.querySelector('.inline-script-stats');
if (!list) return;
const dt = document.createElement('dt');
const dd = document.createElement('dd');
dt.className = className;
dd.className = className;
dt.textContent = label;
dd.textContent = '...';
list.lastElementChild.parentNode.insertBefore(dt, list.lastElementChild.nextSibling);
dt.after(dd);
return dd;
}
document.querySelectorAll('li[data-script-id]').forEach(script => {
const feedbackElement = addStat(script, 'Feedback', 'script-list-feedback');
const installsElement = addStat(script, 'Installs', 'script-list-installs');
const checksElement = addStat(script, 'Checks', 'script-list-update-checks');
script.dataset.feedbackElement = feedbackElement.id = `feedback-${script.dataset.scriptId}`;
script.dataset.installsElement = installsElement.id = `installs-${script.dataset.scriptId}`;
script.dataset.checksElement = checksElement.id = `checks-${script.dataset.scriptId}`;
});
}
const collectScriptLinks = () =>
Array.from(document.querySelectorAll('li[data-script-id]'))
.map(el => {
const domain = window.location.hostname;
const scriptId = el.getAttribute('data-script-id');
const scriptName = el.getAttribute('data-script-name')
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-');
return {
url: `${domain}/en/scripts/${scriptId}-${scriptName}`,
element: el
};
});
async function fetchStats(scriptInfo) {
const apiUrl = `https://forksapis.vercel.app/${scriptInfo.url}`;
try {
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return await response.json();
} catch (error) {
console.error('Error fetching stats:', error);
return null;
}
}
function updateStats(scriptInfo, stats) {
if (!stats) return;
const element = scriptInfo.element;
const feedbackElement = document.getElementById(element.dataset.feedbackElement);
const installsElement = document.getElementById(element.dataset.installsElement);
const checksElement = document.getElementById(element.dataset.checksElement);
if (feedbackElement) feedbackElement.textContent = formatNumber(stats.feedback);
if (installsElement) installsElement.textContent = formatNumber(stats.installs);
if (checksElement) checksElement.textContent = formatNumber(stats.checks);
}
async function init() {
displayScriptStats();
const scriptInfos = collectScriptLinks();
console.log('Found URLs:', scriptInfos.map(info => info.url));
const fetchPromises = scriptInfos.map(async (scriptInfo) => {
const stats = await fetchStats(scriptInfo);
updateStats(scriptInfo, stats);
});
await Promise.all(fetchPromises);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();