Показывает секунды первую минуту. Обновляет значение каждую секунду. До 1 часа считает время и также каждую минуту обновляет значение без обновления страницы. Воркает на устройстве (нагрузка).
当前为
// ==UserScript==
// @name Lolz.live Dynamic Time
// @namespace http://tampermonkey.net/
// @version 1.2
// @description Показывает секунды первую минуту. Обновляет значение каждую секунду. До 1 часа считает время и также каждую минуту обновляет значение без обновления страницы. Воркает на устройстве (нагрузка).
// @author eretly
// @match https://lolz.live/*
// @match https://lzt.market/*
// @grant none
// ==/UserScript==
(function () {
'use strict';
const activeElements = new WeakMap();
let updateTimer = null;
function pluralize(number, one, few, many) {
number = Math.abs(number);
if (number % 100 >= 11 && number % 100 <= 19) return many;
switch (number % 10) {
case 1: return one;
case 2:
case 3:
case 4: return few;
default: return many;
}
}
function getSafeDiff(timestamp) {
return Math.max(0, Math.floor(Date.now() / 1000) - timestamp);
}
function formatRelativeTime(diff) {
diff = Math.max(0, diff);
if (diff < 60) {
return `${diff} ${pluralize(diff, 'секунду', 'секунды', 'секунд')} назад`;
} else if (diff < 120) {
return 'Минуту назад';
} else if (diff < 3600) {
const mins = Math.floor(diff / 60);
return `${mins} мин. назад`;
}
return null;
}
function formatAbsoluteTime(el) {
const timeStr = el.getAttribute('data-timestring');
if (!timeStr) return null;
return `Сегодня, в ${timeStr}`;
}
function updateTimes() {
let needsUpdate = false;
document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
if (!activeElements.has(el)) return;
const timestamp = parseInt(el.getAttribute('data-time'));
const diff = getSafeDiff(timestamp);
if (diff < 3600) {
const newText = formatRelativeTime(diff);
if (newText && el.textContent !== newText) {
el.textContent = newText;
}
needsUpdate = true;
} else if (diff >= 3600) {
const absText = formatAbsoluteTime(el);
if (absText) {
el.textContent = absText;
}
activeElements.delete(el);
}
});
if (needsUpdate && !updateTimer) {
updateTimer = setTimeout(() => {
updateTimer = null;
updateTimes();
}, 1000);
} else if (!needsUpdate && updateTimer) {
clearTimeout(updateTimer);
updateTimer = null;
}
}
function processNewElement(el) {
const currentText = el.textContent;
if (/сегодня|вчера|\d{1,2} \w+ \d{4}/i.test(currentText)) return false;
const timestamp = parseInt(el.getAttribute('data-time'));
const diff = getSafeDiff(timestamp);
if (diff < 3600) {
el.setAttribute('data-original-text', currentText);
const newText = formatRelativeTime(diff);
if (newText) el.textContent = newText;
activeElements.set(el, true);
return true;
}
return false;
}
const observer = new MutationObserver(mutations => {
let shouldUpdate = false;
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) {
const timeNodes = node.matches('abbr.DateTime[data-time]')
? [node]
: Array.from(node.querySelectorAll('abbr.DateTime[data-time]'));
timeNodes.forEach(el => {
if (processNewElement(el)) {
shouldUpdate = true;
}
});
}
});
});
if (shouldUpdate) {
setTimeout(updateTimes, 50);
}
});
function init() {
let needsUpdate = false;
document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
if (processNewElement(el)) {
needsUpdate = true;
}
});
if (needsUpdate) {
updateTimes();
}
observer.observe(document.body, {
childList: true,
subtree: true
});
['click', 'scroll', 'mousemove'].forEach(event => {
document.addEventListener(event, () => {
setTimeout(updateTimes, 100);
}, { passive: true });
});
}
if (document.readyState === 'complete') {
init();
} else {
window.addEventListener('load', init);
}
window.addEventListener('unload', () => {
observer.disconnect();
if (updateTimer) clearTimeout(updateTimer);
});
})();