diff options
| author | Pinapelz <yukais@pinapelz.com> | 2025-12-17 13:40:45 -0800 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2025-12-17 13:40:45 -0800 |
| commit | 0c5cf111b3d59474825d07224598637c9d34c481 (patch) | |
| tree | 842d8e24eb75bea23df5375622ccc0bcd2672dcd /scripts/dancerush/flower/dancerush_flower_scraper.user.js | |
| parent | cc197c39c06eabcb3cb38fc7cca6b13792b137d5 (diff) | |
Diffstat (limited to 'scripts/dancerush/flower/dancerush_flower_scraper.user.js')
| -rw-r--r-- | scripts/dancerush/flower/dancerush_flower_scraper.user.js | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/scripts/dancerush/flower/dancerush_flower_scraper.user.js b/scripts/dancerush/flower/dancerush_flower_scraper.user.js new file mode 100644 index 0000000..97c6083 --- /dev/null +++ b/scripts/dancerush/flower/dancerush_flower_scraper.user.js @@ -0,0 +1,152 @@ +// ==UserScript== +// @name DANCERUSH STARDOM (Flower/Eagle) Play History Scraper + Artist +// @version 1.1 +// @description Export DANCERUSH scores including full judgements, timestamps, and fetched Artist names as JSON +// @match https://eagle.ac/game/dancerush/profile/* +// @downloadUrl https://github.com/pinapelz/Mirage/raw/refs/heads/main/scripts/dancerush/flower/dancerush_flower_scraper.user.js +// @grant none +// ==/UserScript== + +(function() { + 'use strict'; + + const artistCache = {}; + + const btn = document.createElement('button'); + btn.textContent = 'Mirage Export Dancerush JSON'; + btn.style.position = 'fixed'; + btn.style.top = '10px'; + btn.style.right = '10px'; + btn.style.zIndex = 9999; + btn.style.padding = '8px 12px'; + btn.style.background = '#00bcd4'; + btn.style.color = 'white'; + btn.style.border = 'none'; + btn.style.borderRadius = '4px'; + btn.style.cursor = 'pointer'; + btn.style.fontWeight = 'bold'; + document.body.appendChild(btn); + + btn.addEventListener('click', async () => { + const originalText = btn.textContent; + btn.disabled = true; + btn.style.background = '#9e9e9e'; + btn.textContent = 'Processing (Fetching Artists)...'; + + try { + const scores = await parseDancerushLog(); + const blob = new Blob([JSON.stringify(scores, null, 2)], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `dancerush_scores_${Date.now()}.json`; + a.click(); + URL.revokeObjectURL(url); + } catch (error) { + console.error("Scraping failed:", error); + alert("An error occurred while fetching song details. Check console."); + } finally { + btn.textContent = originalText; + btn.disabled = false; + btn.style.background = '#00bcd4'; + } + }); + + async function fetchArtistName(url) { + if (!url) return "Unknown Artist"; + if (artistCache[url]) return artistCache[url]; + + try { + const response = await fetch(url); + const html = await response.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(html, 'text/html'); + + // Find the table row that contains "Song Artist" + const rows = Array.from(doc.querySelectorAll('table.table tr')); + const artistRow = rows.find(r => r.querySelector('th')?.innerText.includes('Song Artist')); + const artistName = artistRow?.querySelector('td b')?.innerText.trim() || "Unknown Artist"; + + artistCache[url] = artistName; + return artistName; + } catch (e) { + console.warn(`Could not fetch artist for ${url}`, e); + return "Unknown Artist"; + } + } + + async function parseDancerushLog() { + const rows = document.querySelectorAll('table.table tbody tr.accordion-toggle'); + const scores = []; + for (let index = 0; index < rows.length; index++) { + const row = rows[index]; + const titleElem = row.querySelector('td.text-right.text-middle strong'); + const diffElem = row.querySelector('td.success div strong'); + const scoreElem = row.querySelector('td:nth-child(4) strong'); + const lampElem = row.querySelector('td:nth-child(5) strong'); + const timestampElem = row.querySelector('td.text-right small'); + const songLink = row.querySelector('td.text-right.text-middle a')?.href || ""; + const artistName = await fetchArtistName(songLink); + + const targetId = row.getAttribute('data-target')?.replace('#', ''); + const detailContainer = document.getElementById(targetId); + + let judgements = { perfect: 0, great: 0, good: 0, bad: 0 }; + let maxCombo = 0; + + if (detailContainer) { + const statDivs = detailContainer.querySelectorAll('div.col-sm-1'); + statDivs.forEach(div => { + const label = div.querySelector('strong')?.innerText.trim(); + const value = parseInt(div.innerHTML.split('<br>')[1]) || 0; + + if (label === 'Perfect') judgements.perfect = value; + if (label === 'Great') judgements.great = value; + if (label === 'Good') judgements.good = value; + if (label === 'Bad') judgements.bad = value; + if (label === 'Combo') maxCombo = value; + }); + } + + const diffText = diffElem ? diffElem.innerText.trim().split(/\s+/) : ["UNKNOWN", "0"]; + const diffLamp = diffText[0]; + const difficultyLevel = parseInt(diffText[1]); + const rawScorePercent = parseFloat(scoreElem?.innerText.trim()) || 0; + const scoreInt = Math.round(rawScorePercent * 1000); + + let lampId = 4; + if (lampElem?.innerText.includes("Full Combo")) lampId = 5; + if (lampElem?.innerText.includes("Excellent")) lampId = 6; + if (lampElem?.innerText.includes("Failed")) lampId = 1; + + let timestampMs = Date.now(); + if (timestampElem) { + timestampMs = new Date(timestampElem.innerText.trim()).getTime(); + } + + scores.push({ + timestamp: timestampMs, + lamp: lampId, + score: scoreInt, + title: titleElem?.innerText.trim() || "Unknown", + artist: artistName, + optional: { + maxCombo: maxCombo + }, + diff_lamp: diffLamp, + timestamp: timestampMs, + difficulty: difficultyLevel, + judgements: judgements, + num_players: 1 + }); + } + return { + "meta": { + "game": "dancerush", + "playtype": "Single", + "service": "FLOWER/EAGLE Dancerush Export", + }, + "scores": scores + }; + } +})(); |
