mirror of
https://gitea.tendokyu.moe/pinapelz/more-tachi-import-scripts.git
synced 2026-09-22 22:28:25 +03:00
mai2: add tachi to tachi session bookmarklet
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# maimai DX Tachi to Tachi
|
||||
|
||||
This is a bookmarklet that will allow you to download data shown in the Web UI of Tachi into a `Batch-Manual` compatible form again.
|
||||
|
||||
This can be handy if you want to download/save data from the MYT network if you are already in a Tachi instance that has integrations with it.
|
||||
|
||||
# Scripts
|
||||
|
||||
## `tachi_to_tachi_session.js`
|
||||
For a singular session. Choose the session to export and go to the `All Scores` tab
|
||||
Page: `https://my-tachi-instance.com/u/USERNAME/games/chunithm/Single/sessions/SESSION_ID`
|
||||
|
||||
# Usage
|
||||
|
||||
1. Copy the contents of the script you want to use
|
||||
2. Create a new bookmark and paste the full contents of the script into the URL section
|
||||
3. Navigate to the relevant score page as shown in the previous section
|
||||
4. Show as many scores as possible on a singular view, if you exceed the largest limit then repeat the steps above for the next page(s)
|
||||
@@ -0,0 +1,104 @@
|
||||
javascript:void(async function () {
|
||||
function waitForRows() {
|
||||
return new Promise((resolve) => {
|
||||
const check = () => {
|
||||
const rows = document.querySelectorAll("table tbody tr");
|
||||
if (rows.length > 0) resolve(rows);
|
||||
else setTimeout(check, 500);
|
||||
};
|
||||
check();
|
||||
});
|
||||
}
|
||||
|
||||
const difficultyMap = {
|
||||
"DX Basic": "DX Basic",
|
||||
"DX Advanced": "DX Advanced",
|
||||
"DX Expert": "DX Expert",
|
||||
"DX Master": "DX Master",
|
||||
"DX Re:Master": "DX Re:Master"
|
||||
};
|
||||
|
||||
const lampMap = {
|
||||
"FAILED": "FAILED",
|
||||
"CLEAR": "CLEAR",
|
||||
"FULL COMBO": "FULL COMBO",
|
||||
"FULL COMBO+": "FULL COMBO+",
|
||||
"ALL PERFECT": "ALL PERFECT",
|
||||
"ALL PERFECT+": "ALL PERFECT+"
|
||||
};
|
||||
|
||||
const gradeList = ["D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+"];
|
||||
|
||||
const rows = await waitForRows();
|
||||
|
||||
const results = {
|
||||
meta: {
|
||||
game: "maimaidx",
|
||||
playtype: "Single",
|
||||
service: "Tachi to Tachi PB Export"
|
||||
},
|
||||
scores: []
|
||||
};
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const row = rows[i];
|
||||
if (row.classList.contains("expandable-pseudo-row") || row.classList.contains("fake-row")) continue;
|
||||
|
||||
const cells = row.querySelectorAll("td");
|
||||
if (cells.length < 9) continue;
|
||||
|
||||
const difficultyText = cells[0].innerText.split("\n")[0].trim();
|
||||
const difficulty = Object.keys(difficultyMap).find(d => difficultyText.includes(d)) || difficultyText;
|
||||
|
||||
const titleAnchor = cells[2].querySelector("a");
|
||||
const title = titleAnchor?.childNodes[0]?.textContent.trim() || "";
|
||||
const artist = titleAnchor?.querySelector("small")?.textContent.trim() || "";
|
||||
|
||||
const percentText = cells[3].innerText.trim();
|
||||
const percent = parseFloat(percentText.match(/([\d.]+)%/)?.[1]) || 0;
|
||||
const grade = gradeList.find(g => percentText.includes(g)) || "D";
|
||||
|
||||
const judgmentSpans = cells[4].querySelectorAll("span");
|
||||
const [pcrit, perfect, great, good, miss] = Array.from(judgmentSpans).map(span => parseInt(span.textContent.trim()));
|
||||
|
||||
const lampText = cells[5].innerText.trim();
|
||||
const lamp = lampMap[lampText] || "FAILED";
|
||||
|
||||
const timeText = cells[7].querySelector("small")?.textContent?.trim();
|
||||
let timeAchieved = null;
|
||||
if (timeText) {
|
||||
const parsed = new Date(timeText);
|
||||
if (!isNaN(parsed)) {
|
||||
timeAchieved = parsed.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
const score = {
|
||||
identifier: title,
|
||||
artist,
|
||||
difficulty,
|
||||
percent,
|
||||
lamp,
|
||||
judgements: {
|
||||
pcrit,
|
||||
perfect,
|
||||
great,
|
||||
good,
|
||||
miss
|
||||
},
|
||||
matchType: "songTitle",
|
||||
timeAchieved: timeAchieved
|
||||
};
|
||||
|
||||
results.scores.push(score);
|
||||
}
|
||||
|
||||
const blob = new Blob([JSON.stringify(results, null, 2)], { type: "application/json" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "maimaidx_session_scores.json";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
})();
|
||||
Reference in New Issue
Block a user