aboutsummaryrefslogtreecommitdiffstats
path: root/mai2/tachi/tachi_to_tachi_session.js
blob: f9befa5444a777d83385cb54a66cdb23a33f2863 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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);
})();
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage