您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically displays the time taken between dungeon runs in Milky Way Idle chat.
// ==UserScript== // @name MWI Dungeon Timer // @namespace http://tampermonkey.net/ // @version 0.2 // @author qu // @description Automatically displays the time taken between dungeon runs in Milky Way Idle chat. // @match https://www.milkywayidle.com/* // @match https://test.milkywayidle.com/* // @license MIT // @run-at document-idle // ==/UserScript== (function bootstrap() { if (typeof window.MWITools_marketAPI_json !== 'undefined') { (function waitForCompat() { if (typeof window.MWITools_marketAPI_json === 'undefined') { return setTimeout(waitForCompat, 200); } initDungeonTimer(); })(); } else { initDungeonTimer(); } })(); function initDungeonTimer() { 'use strict'; const MSG_SEL = '[class^="ChatMessage_chatMessage"]'; const KEY_COUNTS_RE = /^\[(\d{1,2}):(\d{2}):(\d{2}) ([AP]M)\] Key counts: /; const previousTimes = []; let lastKeyTime = null; let runStatus = 'ok'; // options: 'ok', 'canceled', 'failed' let lastUrl = location.href; function getChatText(msg) { const full = msg.textContent.trim(); return full.replace(/^\[\d{1,2}:\d{2}:\d{2} [AP]M\]\s+\S+:\s*/, ''); } function getTimestampFromMessage(msg) { const match = msg.textContent.trim().match(/^\[(\d{1,2}):(\d{2}):(\d{2}) ([AP]M)\]/); if (!match) return null; let [_, hour, min, sec, period] = match; hour = parseInt(hour, 10); min = parseInt(min, 10); sec = parseInt(sec, 10); // Convert to 24-hour time if (period === 'PM' && hour !== 12) hour += 12; if (period === 'AM' && hour === 12) hour = 0; const date = new Date(); date.setHours(hour, min, sec, 0); return date; } function formatTimeDiff(ms) { const totalSeconds = Math.floor(ms / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; return `${minutes}m ${seconds}s`; } function insertDungeonTimer(label, msg) { if (msg.dataset.timerAppended === '1') return; const spans = msg.querySelectorAll('span'); if (spans.length < 2) return; const messageSpan = spans[1]; const timerSpan = document.createElement('span'); timerSpan.textContent = ` [${label}]`; if (label === 'FAILED') { timerSpan.style.color = '#ff4c4c'; // red } else if (label === 'canceled') { timerSpan.style.color = '#ffd700'; // yellow } else { timerSpan.style.color = '#90ee90'; // light green } timerSpan.style.fontSize = '90%'; timerSpan.style.fontStyle = 'italic'; messageSpan.appendChild(timerSpan); msg.dataset.timerAppended = '1'; } function isCharacterUrl(url) { return /^https:\/\/www\.milkywayidle\.com\/game\?characterId=\d+$/.test(url); } function isBattleEndedMessage(msg) { return /\[\d{1,2}:\d{2}:\d{2} [AP]M\] Battle ended: /.test(msg.textContent); } function isPartyFailedMessage(msg) { return /\[\d{1,2}:\d{2}:\d{2} [AP]M\] Party failed on wave \d+/.test(msg.textContent); } function processKeyCountMessage(msg) { const timestamp = getTimestampFromMessage(msg); if (!timestamp) return; msg.dataset.processed = '1'; if (lastKeyTime) { if (runStatus === 'failed') { insertDungeonTimer('FAILED', msg); } else if (runStatus === 'canceled') { insertDungeonTimer('canceled', msg); } else { let diff = lastKeyTime - timestamp; if (timestamp > lastKeyTime) { diff += 24 * 60 * 60 * 1000; // handle midnight rollover } const diffStr = formatTimeDiff(diff); insertDungeonTimer(diffStr, msg); } } // Always update lastKeyTime and reset battle flag lastKeyTime = timestamp; runStatus = 'ok'; // reset for next run } function scanExistingMessages() { const messages = Array.from(document.querySelectorAll(MSG_SEL)).reverse(); previousTimes.length = 0; // Reset time tracking for (const msg of messages) { if (isBattleEndedMessage(msg)) { runStatus = 'canceled'; continue; } if (isPartyFailedMessage(msg)) { runStatus = 'failed'; continue; } if (msg.dataset.processed === '1') continue; const raw = getChatText(msg); if (!KEY_COUNTS_RE.test(raw)) continue; processKeyCountMessage(msg); } console.log('[DungeonTimer] Scanned existing messages'); } const observer = new MutationObserver(mutations => { for (const mutation of mutations) { const newUrl = location.href; if (newUrl !== lastUrl && isCharacterUrl(newUrl)) { lastUrl = newUrl; initDungeonTimer(); } for (const node of mutation.addedNodes) { if (!(node instanceof HTMLElement)) continue; const msg = node.matches?.(MSG_SEL) ? node : node.querySelector?.(MSG_SEL); if (!msg || msg.dataset.processed === '1') continue; const raw = getChatText(msg); if (!KEY_COUNTS_RE.test(raw)) continue; processKeyCountMessage(msg); } } }); observer.observe(document.body, { childList: true, subtree: true }); setTimeout(scanExistingMessages, 1500); // Wait for the chat to load console.log('[DungeonTimer] ready'); }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址