Show total working stats with API key prompt
当前为
// ==UserScript==
// @name Torn Profile Workstats Viewer
// @namespace http://tampermonkey.net/
// @version 1.1
// @description Show total working stats with API key prompt
// @match https://www.torn.com/profiles.php
// @grant GM_xmlhttpRequest
// @grant GM_setValue
// @grant GM_getValue
// @connect api.torn.com
// @author aquagloop
// @license MIT
// ==/UserScript==
(function () {
'use strict';
const getApiKey = () => {
// Try to get saved API key
let apiKey = GM_getValue('torn_api_key', '');
// If no saved key, prompt for it
if (!apiKey) {
apiKey = prompt('Please enter your Torn API key:');
if (apiKey) {
// Save the key for future use
GM_setValue('torn_api_key', apiKey.trim());
}
}
return apiKey;
};
const clearApiKey = () => {
GM_setValue('torn_api_key', '');
};
const getProfileId = () => {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('XID');
};
const fetchWorkStats = (userId, apiKey) => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url: `https://api.torn.com/v2/user/${userId}/hof?key=${apiKey}`,
headers: {
Accept: 'application/json'
},
onload: (response) => {
try {
const data = JSON.parse(response.responseText);
if (data.error) {
// If API key error, clear saved key
if (data.error.code === 2) {
clearApiKey();
}
reject(data.error.error);
} else {
resolve(data.hof?.working_stats?.value || 0);
}
} catch (e) {
reject('Failed to parse response');
}
},
onerror: () => reject('Network error')
});
});
};
const displayStats = (total) => {
// Remove existing box if present
const existingBox = document.getElementById('workstatsBox');
if (existingBox) {
existingBox.remove();
}
const box = document.createElement('div');
box.id = 'workstatsBox';
Object.assign(box.style, {
position: 'fixed',
top: '20px',
right: '20px',
background: 'rgba(0,0,0,0.85)',
color: '#fff',
padding: '14px 18px',
borderRadius: '12px',
fontFamily: 'Arial, sans-serif',
fontSize: '14px',
zIndex: '9999',
boxShadow: '0 0 10px rgba(0,0,0,0.5)',
textAlign: 'center',
});
box.innerHTML = `
<strong>Total Working Stats</strong><br>
<span style="font-size: 18px;">${total.toLocaleString()}</span>
`;
// Add settings button
const settingsBtn = document.createElement('button');
settingsBtn.innerHTML = '⚙️';
settingsBtn.title = 'Change API Key';
Object.assign(settingsBtn.style, {
position: 'absolute',
top: '2px',
right: '2px',
background: 'transparent',
border: 'none',
color: '#fff',
cursor: 'pointer',
fontSize: '10px',
padding: '2px'
});
settingsBtn.addEventListener('click', () => {
if (confirm('Do you want to change your API key?')) {
clearApiKey();
location.reload();
}
});
box.appendChild(settingsBtn);
document.body.appendChild(box);
};
const displayError = (error) => {
// Remove existing box if present
const existingBox = document.getElementById('workstatsBox');
if (existingBox) {
existingBox.remove();
}
const box = document.createElement('div');
box.id = 'workstatsBox';
Object.assign(box.style, {
position: 'fixed',
top: '20px',
right: '20px',
background: 'rgba(255,0,0,0.85)',
color: '#fff',
padding: '14px 18px',
borderRadius: '12px',
fontFamily: 'Arial, sans-serif',
fontSize: '12px',
zIndex: '9999',
boxShadow: '0 0 10px rgba(0,0,0,0.5)',
textAlign: 'center',
maxWidth: '200px'
});
box.innerHTML = `
<strong>Error</strong><br>
<span style="font-size: 11px;">${error}</span><br>
<button id="retryBtn" style="margin-top: 8px; padding: 4px 8px; background: #fff; color: #000; border: none; border-radius: 4px; cursor: pointer;">
Retry
</button>
`;
document.body.appendChild(box);
document.getElementById('retryBtn').addEventListener('click', () => {
box.remove();
main();
});
};
const main = async () => {
const userId = getProfileId();
if (!userId) return;
const apiKey = getApiKey();
if (!apiKey) {
console.log('No API key provided');
return;
}
try {
const totalStats = await fetchWorkStats(userId, apiKey);
displayStats(totalStats);
} catch (error) {
console.error('Workstats error:', error);
displayError(error);
}
};
// Run when page loads
window.addEventListener('load', main);
// Also run when URL changes (for navigation within Torn)
let currentUrl = window.location.href;
setInterval(() => {
if (window.location.href !== currentUrl) {
currentUrl = window.location.href;
setTimeout(main, 500);
}
}, 1000);
})();