flowerpicker 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +17 -12
  2. package/convert.js +36 -0
  3. package/index.js +16 -4
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@ Currently only Jubeat is supported as far as games go.
9
9
 
10
10
  Below is some example code with their explanations to get started:
11
11
  ```js
12
- import FlowerPicker from "../FlowerPicker/index.js";
12
+ import FlowerPicker, { convert } from "flowerpicker";
13
13
 
14
14
  // The constructor has 2 parameters: The url to the server dashboard, and your cookie to said dashboard
15
15
  const SESSION_COOKIE = "abc123";
@@ -25,6 +25,11 @@ await picker.setupJubeatScoreLog();
25
25
  // This is an example of how to export the score log from the package to a text file
26
26
  // Temporarily incredibly scuffed as I get the basic functionality up and running
27
27
  fs.writeFileSync(`./data/data-${Date.now()}-${picker._gameScoreLogs.jubeat.length}.json`, JSON.stringify(picker._gameScoreLogs.jubeat, null, 2) , 'utf-8');
28
+
29
+ // To convert an export to a tachi-compatible JSON, you can use the convert module
30
+ // The first parameter is the JSON file, the second what you want the service to show up as imported from
31
+ const convertedJubeat = await picker.convert.jubeatToTachiCompat(JSON.parse(fs.readFileSync(fileName, 'utf-8')), "FlowerPicker-FLO");
32
+ fs.writeFileSync('converted.json', JSON.stringify(convertedJubeat, null, 2), 'utf-8');
28
33
  ```
29
34
 
30
35
  ## Supported data (Accessible via the package)
@@ -40,17 +45,17 @@ The following account information is accessible via this package:
40
45
 
41
46
  The following games may not be updated by me, PRs may be reviewed and accepted
42
47
 
43
- | Game | Profile Information[^1] | Score Log | Game Specific Data |
44
- | :------------------------------ | :---------------------: | :-------: | :----------------: |
45
- | beatmania IIDX | ❌ | ❌ | ❌ |
46
- | DanceDanceRevolution | ❌ | ❌ | ❌ |
47
- | GITADORA | ❌ | ❌ | ❌ |
48
- | Jubeat | ⚠️[^2] | ✅ | ❌[^3] |
49
- | NOSTALGIA | ❌ | ❌ | ❌ |
50
- | pop'n music | ❌ | ❌ | ❌ |
51
- | REFLEC BEAT | ❌ | ❌ | ❌ |
52
- | Sound Voltex | ❌ | ❌ | ❌ |
53
- | PASELI Charging Machine (Soon™️) | ❌ | ❌ | ❌ |
48
+ | Game | Profile Information[^1] | Score Log | Game Specific Data | Tachi Export |
49
+ | :------------------------------ | :---------------------: | :-------: | :----------------: | :----------: |
50
+ | beatmania IIDX | ❌ | ❌ | ❌ | ❌ |
51
+ | DanceDanceRevolution | ❌ | ❌ | ❌ | ❌ |
52
+ | GITADORA | ❌ | ❌ | ❌ | ❌ |
53
+ | Jubeat | ⚠️[^2] | ✅ | ❌[^3] | ✅ |
54
+ | NOSTALGIA | ❌ | ❌ | ❌ | ❌ |
55
+ | pop'n music | ❌ | ❌ | ❌ | ❌ |
56
+ | REFLEC BEAT | ❌ | ❌ | ❌ | ❌ |
57
+ | Sound Voltex | ❌ | ❌ | ❌ | ❌ |
58
+ | PASELI Charging Machine (Soon™️) | ❌ | ❌ | ❌ | ❌ |
54
59
 
55
60
  [^1]: Profile information includes profile id(s) on the site, game display name, and unlock statuses
56
61
 
package/convert.js ADDED
@@ -0,0 +1,36 @@
1
+ export function jubeatToTachiCompat(jubeatDataJSON, service) {
2
+ // Thank you to https://gist.github.com/Meta-link/d01c15fc56a277becc7d67a7c1dccfa2 for the tachi structure
3
+ let tachiCompJson = {
4
+ meta: {
5
+ "game": "jubeat",
6
+ "playtype": "Single",
7
+ "service": service ? service : "FlowerPicker",
8
+ },
9
+ scores: []
10
+ };
11
+
12
+ jubeatDataJSON.forEach((item) => {
13
+ tachiCompJson.scores.push({
14
+ "score": Number(item.songNumberScore),
15
+ "lamp": item.songClearStatus.toUpperCase(), // Values returned by the scraper are the same, just not in uppercase
16
+ "musicRate": Number(item.songMusicRate.replace('%', '')), // Jubeat specific field :)
17
+ "matchType": "inGameID",
18
+ "identifier": item.songID,
19
+ "difficulty": (item.songIsHardPlay ? "HARD " : "") + item.songChart.split(' ')[0], // Returns "ABC 1.1", so this shouldn't be a problem
20
+ "timeAchieved": Math.floor(new Date(item.songTimestampString).getTime()),
21
+ "judgements": {
22
+ "perfect": Number(item.scoreData.perfects),
23
+ "great": Number(item.scoreData.greats),
24
+ "good": Number(item.scoreData.goods),
25
+ "poor": Number(item.scoreData.poors),
26
+ "miss": Number(item.scoreData.misses)
27
+ },
28
+ "optional": {
29
+ "maxCombo": Number(item.songMaxCombo),
30
+ "musicBar": item.judgeBar
31
+ }
32
+ });
33
+ });
34
+
35
+ return tachiCompJson;
36
+ }
package/index.js CHANGED
@@ -94,17 +94,17 @@ class FlowerPicker {
94
94
  poors: this._trimToNumber($(songTrDiv).find("div:contains('Poors')").text()),
95
95
  misses: this._trimToNumber($(songTrDiv).find("div:contains('Misses')").text()),
96
96
  };
97
+ let judgeBar = $(songTrDiv).find(".jubeat-bars").attr("data-jubeat-judge").split(" ").map(Number);
97
98
  let onPage = i;
98
99
 
99
100
  scoreArray.push({
100
101
  playID, songTitle, songID, songDifficultyID, songIsHardPlay, songChart,
101
102
  songLetterScore, songNumberScore, songMusicRate, songJubility,
102
103
  songClearStatus, songMaxCombo, songTimestampString,
103
- arcadePlayedAtString, arcadePlayedAtID, machinePlayedWithString, scoreData, onPage
104
+ arcadePlayedAtString, arcadePlayedAtID, machinePlayedWithString, scoreData, judgeBar, onPage
104
105
  });
105
106
  });
106
107
 
107
- scoreArray.reverse();
108
108
  this._gameScoreLogs.jubeat.push(...scoreArray); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
109
109
  })
110
110
  // FIXME: This one as well
@@ -113,6 +113,17 @@ class FlowerPicker {
113
113
  });
114
114
  }
115
115
 
116
+ async getProfileId(game, id) {
117
+ const res = await this._fetchWithCookie(`${this._baseURL}/game/${game}/profile/${id}`);
118
+ const html = await res.text();
119
+ const $ = cheerio.load(html);
120
+
121
+ const href = $("small > a").first().attr("href");
122
+ if (!href) return null;
123
+
124
+ return href.split("/")[4] ?? null;
125
+ }
126
+
116
127
  async _fetchWithCookie(url) {
117
128
  return fetch(url, {
118
129
  headers: {
@@ -201,7 +212,7 @@ class FlowerPicker {
201
212
  let walletID = theElement.attr('href')?.split('/').pop();
202
213
  let walletBalance = this._trimToNumber(theElement.children('.list-group-item-text').text());
203
214
 
204
- walletIDs.push({arcadeName, walletID, walletBalance});
215
+ walletIDs.push({ arcadeName, walletID, walletBalance });
205
216
  });
206
217
 
207
218
  return walletIDs;
@@ -213,4 +224,5 @@ class FlowerPicker {
213
224
  }
214
225
  }
215
226
 
216
- export default FlowerPicker;
227
+ export default FlowerPicker;
228
+ export * as convert from "./convert.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowerpicker",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Data scraper for a certain rhythm game website",
5
5
  "author": "BoopDog",
6
6
  "license": "MIT",