ljovcheg [3191064]
当前为
// ==UserScript==
// @name NearestEventTimer
// @namespace NearestEventTimer
// @version 1.0.5
// @grant GM_getValue
// @grant GM_setValue
// @description ljovcheg [3191064]
// @author ljovcheg [3191064]
// @match https://www.torn.com/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_info
// @license mit
// ==/UserScript==
(function () {
'use strict';
throwError('starting');
GM_addStyle(`
#eventTimer {
background-color: rgba(0, 0, 0, 0.5);
margin-top: 5px;
margin-bottom: 7px;
border-radius: 5px;
padding: 7px;
overflow: hidden;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none;
line-height: 16px;
font-weight: 100;
}
#eventTimer:hover{
background-color: rgba(0, 0, 0, 0.9);
}
`);
let apiKey;
let events;
let userEventStartTime;
let userEventStartTimeUnix;
let nearestEvent;
let div; // timer div object
let timer; // holding timeout
const updateInterval = 1800; //30min
function injectDiv() {
if (document.getElementById("eventTimer")) {
checkCache();
return;
}
let tornClock = document.querySelector(".tc-clock-tooltip");
if (tornClock) {
let p = tornClock.appendChild(document.createElement("div"));
p.addEventListener("click", divClicked);
p.innerHTML = `<div id="eventTimer">...</div>`;
div = document.getElementById('eventTimer');
checkCache();
} else {
throwError(".tc-clock-tooltip not found");
}
}
injectDiv();
function checkCache() {
let currentTimeStamp = Math.round(Date.now() / 1000);
// read cache
apiKey = GM_getValue('timer_api_key', null);
events = GM_getValue('events', null);
userEventStartTime = GM_getValue('userEventStartTime', null);
let lastUpdated = GM_getValue('updated', null);
if (!lastUpdated || currentTimeStamp - lastUpdated > updateInterval || !events || !userEventStartTime) {
if (apiKey) {
fetchData();
} else {
throwError("No api key");
setText("no apy key");
}
} else {
calculate();
}
}
async function fetchData() {
setText("fetching torn...");
const tornData = await GM_fetch('torn', 'calendar');
if (tornData.calendar) {
let json = tornData.calendar;
if (json.events && json.competitions) {
events = json["events"].concat(json.competitions);
} else {
events = json.events;
}
GM_setValue('events', events);
} else if (tornData.error) {
throwError(tornData.error);
setText(tornData.error.error);
return;
}
setText("fetching user...");
const userData = await GM_fetch('user', 'calendar,timestamp');
if (userData.calendar) {
let json = userData.calendar;
if (json.start_time) {
userEventStartTime = json.start_time.toLowerCase().split(" tct")[0];
GM_setValue('userEventStartTime', userEventStartTime);
}
compareTimestamp(userData);
} else if (userData.error) {
throwError(tornData.error);
setText(userData.error.error);
return;
}
let currentTimeStamp = Math.round(Date.now() / 1000);
GM_setValue('updated', currentTimeStamp);
calculate();
}
async function GM_fetch(page, selections) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: `https://api.torn.com/v2/${page}/?selections=${selections}&key=${apiKey}`,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
onload: function (response) {
try {
if (!response || !response.responseText) {
return reject(new Error("Empty response"));
}
const json = JSON.parse(response.responseText);
resolve(json);
} catch (err) {
reject(err);
}
},
onerror: function (err) {
reject(err);
},
});
});
}
function calculate() {
let currentTimeStamp = Math.round(Date.now() / 1000);
nearestEvent = getNearestEvent(events, currentTimeStamp);
if (nearestEvent) {
userEventStartTimeUnix = setTimeOnUnix(nearestEvent.start, userEventStartTime);
doTimer();
}
}
function doTimer() {
let currentTimeStamp = Math.round(Date.now() / 1000);
let dif = userEventStartTimeUnix - currentTimeStamp;
let str = secondsToTime(dif);
setText(`
${nearestEvent.title}<br>
<b>in: ${str.hours}:${str.minutes}:${str.seconds}</b>
`);
if (!timer) timer = setInterval(doTimer, 1000);
}
function secondsToTime(totalSeconds) {
const hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
const paddedHours = hours < 10 ? "0" + hours : hours;
const paddedMinutes = minutes < 10 ? "0" + minutes : minutes;
const paddedSeconds = seconds < 10 ? "0" + seconds : seconds;
return {
hours: paddedHours,
minutes: paddedMinutes,
seconds: paddedSeconds,
};
}
function getNearestEvent(events, current_time) {
let longestWord = ""; // for testing
if (!events || events.length === 0) return null;
let dummyList = []; // no idea why sice doesn't work
for (let i = 0; i < events.length; i++) {
let event = events[i];
let diff = (event.start - current_time);
let eventTitle = event.title;
if (eventTitle.length > longestWord.length) longestWord = eventTitle;
event.diff = diff;
if (diff >= 0) {
dummyList.push(event);
}
}
events = dummyList;
events.sort(function (a, b) {
return a.diff - b.diff;
});
let nearestEvent = events[0];
let minDifference = Math.abs(events[0].start - current_time);
for (let i = 1; i < events.length; i++) {
const diff = Math.abs(events[i].start - current_time);
if (diff < minDifference) {
minDifference = diff;
nearestEvent = events[i];
}
}
return nearestEvent;
}
function setTimeOnUnix(unixTime, timeString) {
const [targetHour, targetMinute] = timeString.split(":").map(Number);
const date = new Date(unixTime * 1000);
date.setUTCHours(targetHour);
date.setUTCMinutes(targetMinute);
date.setUTCSeconds(0);
date.setUTCMilliseconds(0);
return Math.floor(date.getTime() / 1000);
}
function divClicked() {
let w = prompt("Api key", apiKey);
if (w || w === "" && w !== null) {
//save key
GM_setValue('timer_api_key', w);
apiKey = w;
}
if (apiKey && w !== null) fetchData();
}
function setText(data) {
div.innerHTML = data;
}
function throwError(data) {
console.log(`%cnextEvent${(typeof data !== 'object') ? ': ' + data : ''}`, 'background: #e83c3cff; color: white;padding:10px; border-radius:3px;', (typeof data === 'object') ? data : '');
}
function compareTimestamp(data) {
if (!data.timestamp) return;
return; //TODO
let uts = data.timestamp;
let lts = Math.round(Date.now() / 1000);
if (uts !== lts) {
console.log(uts - lts);
}
let dif = uts - lts;
console.log({
"user torn timestamp": uts,
"local timestamp": lts,
"same": (uts === lts)
});
}
})();