diff options
| author | Pinapelz <yukais@pinapelz.com> | 2025-04-12 20:50:11 -0700 |
|---|---|---|
| committer | Pinapelz <yukais@pinapelz.com> | 2025-04-12 20:50:11 -0700 |
| commit | 4e82e56b49b1b83949a56ac8be2630008180ef93 (patch) | |
| tree | 339d0da6f8d7bd84d221b732bee33bedc2f5fbf3 | |
| parent | b12b662e3644c6a387468da698fddcb93b1dbcf9 (diff) | |
ongeki tachi_to_tachi session
| -rw-r--r-- | ongeki/tachi/tachi_to_tachi_session.js | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/ongeki/tachi/tachi_to_tachi_session.js b/ongeki/tachi/tachi_to_tachi_session.js new file mode 100644 index 0000000..76e64e4 --- /dev/null +++ b/ongeki/tachi/tachi_to_tachi_session.js @@ -0,0 +1,91 @@ +javascript:(function() { + function toUnixMillis(s) { + try { return new Date(s).getTime(); } + catch { return null; } + } + + const rows = document.querySelectorAll("table tbody tr"); + const scores = []; + + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if (!row || row.classList.contains("expandable-pseudo-row") || row.classList.contains("fake-row")) continue; + + const cells = row.querySelectorAll("td"); + if (cells.length < 9) continue; + + let chartText = cells[0].querySelector("div.d-none.d-lg-block")?.textContent.trim() || ""; + let chart = chartText.split(/\s+/)[0].toUpperCase(); + if (chart === "EXP") chart = "EXPERT"; + if (!["BASIC", "ADVANCED", "EXPERT", "MASTER", "LUNATIC"].includes(chart)) continue; + + const anchor = cells[2].querySelector("a"); + if (!anchor) continue; + + const [titleHtml, artistHtml] = anchor.innerHTML.split("<br>"); + const temp = document.createElement("div"); + temp.innerHTML = titleHtml; + const title = temp.textContent.trim(); + temp.innerHTML = artistHtml || ""; + const artist = temp.textContent.trim(); + + const scoreText = cells[3].innerText.trim().split("\n").pop().replace(/,/g, ""); + const score = parseInt(scoreText, 10); + if (isNaN(score)) continue; + + const noteLamp = (cells[6].innerText.trim() || "UNKNOWN").toUpperCase(); + + const smallTags = cells[8].querySelectorAll("small"); + let timeAchieved = null; + if (smallTags.length > 0) { + timeAchieved = toUnixMillis(smallTags[0].textContent.trim()); + } + + let cbreak = 0, breaks = 0, hit = 0, miss = 0, bellCount = 0, totalBellCount = 0, damage = 0; + const judgementSpans = cells[5].querySelectorAll("span"); + if (judgementSpans.length >= 4) { + cbreak = parseInt(judgementSpans[0].textContent) || 0; + breaks = parseInt(judgementSpans[1].textContent) || 0; + hit = parseInt(judgementSpans[2].textContent) || 0; + miss = parseInt(judgementSpans[3].textContent) || 0; + } + if (judgementSpans.length >= 6) { + const bellMatch = judgementSpans[4].textContent.match(/(\d+)\/(\d+)/); + if (bellMatch) { + bellCount = parseInt(bellMatch[1]); + totalBellCount = parseInt(bellMatch[2]); + } + damage = parseInt(judgementSpans[5].textContent) || 0; + } + + scores.push({ + score, + noteLamp, + bellLamp: "NONE", + matchType: "songTitle", + identifier: title, + artist, + difficulty: chart, + timeAchieved, + judgements: { cbreak, break: breaks, hit, miss }, + optional: { bellCount, totalBellCount, damage } + }); + } + + const result = { + meta: { + game: "ongeki", + playtype: "Single", + service: "bookmarkelt" + }, + scores + }; + + const blob = new Blob([JSON.stringify(result, null, 2)], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = "ongeki_batch_manual.json"; + a.click(); + URL.revokeObjectURL(url); +})(); |
