gj-boomlings-api 0.1.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.
- package/README.md +0 -0
- package/config.json +1 -0
- package/functions/decURLSafeBase64.js +10 -0
- package/functions/dlLevel.js +239 -0
- package/functions/encURLSafeBase64.js +9 -0
- package/functions/getLevelData.js +29 -0
- package/functions/getOfficialSongInfo.js +90 -0
- package/functions/getSongInfo.js +30 -0
- package/index.js +13 -0
- package/misc/officialsongs.json +273 -0
- package/misc/xor.js +5 -0
- package/package.json +27 -0
package/README.md
ADDED
|
Binary file
|
package/config.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"headers":{"Content-Type":"application/x-www-form-urlencoded","user-agent":""}}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
decURLSafeBase64:
|
|
3
|
+
function(string) {
|
|
4
|
+
const bs = require("js-base64");
|
|
5
|
+
if(!string) throw new Error("No string provided!")
|
|
6
|
+
let str = bs.decode(string.replace(/_/g, '/').replace(/-/g, '+'));
|
|
7
|
+
if(!bs.isValid(str)) throw new Error("The provided string is not encoded in Base64!")
|
|
8
|
+
return str;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
dlLevel:
|
|
3
|
+
async function(level) {
|
|
4
|
+
const bs = require("js-base64")
|
|
5
|
+
if(!level) throw new Error("Please provide a level ID.");
|
|
6
|
+
if(isNaN(level)) throw new Error("The level parameter should be a number.");
|
|
7
|
+
const axios = require("axios");
|
|
8
|
+
const { headers } = require("../config.json");
|
|
9
|
+
|
|
10
|
+
const XOR = require("../misc/xor.js");
|
|
11
|
+
let xor = new XOR()
|
|
12
|
+
|
|
13
|
+
const data = {
|
|
14
|
+
gameVersion: 21,
|
|
15
|
+
binaryVersion: 35,
|
|
16
|
+
gdw: 0,
|
|
17
|
+
levelID: level,
|
|
18
|
+
secret: "Wmfd2893gb7"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let res = await axios.post('http://www.boomlings.com/database/downloadGJLevel22.php', data, {
|
|
22
|
+
headers: headers
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
if(res.data == -1) throw new Error("-1 Not found.")
|
|
26
|
+
if(res.data == "Error code: 1005") throw new Error("1005 error: Your IP address has been blocked from sending requests to a server. It's recommended to use locally (directly from a PC).")
|
|
27
|
+
let split1 = res.data.split("1:")[1]; // id
|
|
28
|
+
let split2 = res.data.split(":2:")[1]; // name
|
|
29
|
+
let split3 = res.data.split(":3:")[1]; // description
|
|
30
|
+
let split4 = res.data.split(":5:")[1]; // level version
|
|
31
|
+
let split5 = res.data.split(":9:")[1]; // difficulty
|
|
32
|
+
let split6 = res.data.split(":18:")[1]; // stars
|
|
33
|
+
let split7 = res.data.split("0:10:")[1]; // downloads
|
|
34
|
+
let split8 = res.data.split(":14:")[1]; // likes
|
|
35
|
+
let split9 = res.data.split(":15:")[1]; // length
|
|
36
|
+
let split10 = res.data.split(":27:")[1]; // password
|
|
37
|
+
let split11 = res.data.split(":17:")[1]; // demon or not
|
|
38
|
+
let split12 = res.data.split(":19:")[1]; // featured
|
|
39
|
+
let split13 = res.data.split(":42:")[1]; // epic
|
|
40
|
+
let split14 = res.data.split(":45:")[1]; // objects
|
|
41
|
+
let split15 = res.data.split(":28:")[1]; // uploaded
|
|
42
|
+
let split16 = res.data.split(":29:")[1]; // updated
|
|
43
|
+
let split17 = res.data.split(":39:")[1]; // stars requested
|
|
44
|
+
let split18 = res.data.split(":40:")[1]; // ldm
|
|
45
|
+
let split19 = res.data.split(":30:")[1]; // copied from
|
|
46
|
+
let split20 = res.data.split(":31:")[1]; // two player
|
|
47
|
+
let split21 = res.data.split(":37:")[1]; // coins
|
|
48
|
+
let split22 = res.data.split(":38:")[1]; // verified coins
|
|
49
|
+
let split23 = res.data.split(":6:")[1]; // player id
|
|
50
|
+
let split24 = res.data.split(":13:")[1]; // game version
|
|
51
|
+
let split25 = res.data.split(":12:")[1]; // official song id
|
|
52
|
+
let split26 = res.data.split(":35:")[1]; // custom song id
|
|
53
|
+
|
|
54
|
+
if(split25.split(":13:")[0].includes(":")) split25 = res.data.split(":12:")[2];
|
|
55
|
+
if(split26.split(":36:")[0].includes(":")) split26 = res.data.split(":35:")[2];
|
|
56
|
+
|
|
57
|
+
let difficultyDecoding = {
|
|
58
|
+
"0": "Unrated",
|
|
59
|
+
"10": "Easy",
|
|
60
|
+
"20": "Normal",
|
|
61
|
+
"30": "Hard",
|
|
62
|
+
"40": "Harder",
|
|
63
|
+
"50": "Insane"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if(split11.split(":43:")[0] == "1") {
|
|
67
|
+
difficultyDecoding = {
|
|
68
|
+
"10": "Easy Demon",
|
|
69
|
+
"20": "Medium Demon",
|
|
70
|
+
"30": "Hard Demon",
|
|
71
|
+
"40": "Insane Demon",
|
|
72
|
+
"50": "Extreme Demon"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const binaryBool = {
|
|
77
|
+
undefined: false,
|
|
78
|
+
"0": false,
|
|
79
|
+
"1": true
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const featuredDecoding = {
|
|
83
|
+
undefined: true,
|
|
84
|
+
"0": false,
|
|
85
|
+
"1": true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let featured = featuredDecoding[split12.split(":42:")[0]];
|
|
89
|
+
if(featured == undefined) featured = true;
|
|
90
|
+
|
|
91
|
+
let demonBool = binaryBool[split11.split(":43:")[0]];
|
|
92
|
+
if(split11.split(":43:")[0] == "") demonBool = false;
|
|
93
|
+
|
|
94
|
+
let ldm = binaryBool[split18.split(":27")[0]]
|
|
95
|
+
if(ldm == undefined) ldm = false;
|
|
96
|
+
|
|
97
|
+
const lengthDecoding = {
|
|
98
|
+
"0": "Tiny",
|
|
99
|
+
"1": "Short",
|
|
100
|
+
"2": "Medium",
|
|
101
|
+
"3": "Long",
|
|
102
|
+
"4": "XL"
|
|
103
|
+
}
|
|
104
|
+
if(lengthDecoding[split9.split(":30:")[0]] == undefined) split9 = res.data.split(":15:")[2];
|
|
105
|
+
|
|
106
|
+
let desc = bs.decode(split3.split(":4:")[0].replace(/_/g, '/').replace(/-/g, '+'));
|
|
107
|
+
if(desc == "") desc = "(No description provided)"
|
|
108
|
+
|
|
109
|
+
let likes = split8.split(":17:")[0];
|
|
110
|
+
let dislikedBool;
|
|
111
|
+
if(likes.includes("-")) {
|
|
112
|
+
dislikedBool = true;
|
|
113
|
+
} else {
|
|
114
|
+
dislikedBool = false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const decryptedPass = xor.decrypt(split10, 26364);
|
|
118
|
+
if (decryptedPass.length > 1) split10 = decryptedPass.slice(1);
|
|
119
|
+
else split10 = decryptedPass;
|
|
120
|
+
if (decryptedPass.length > 7) split10 = "Non-copyable";
|
|
121
|
+
|
|
122
|
+
const authData = {
|
|
123
|
+
gameVersion: 21,
|
|
124
|
+
binaryVersion: 35,
|
|
125
|
+
gdw: 0,
|
|
126
|
+
str: split23.split(":8:")[0],
|
|
127
|
+
secret: "Wmfd2893gb7"
|
|
128
|
+
}
|
|
129
|
+
let auth = await axios.post("http://www.boomlings.com/database/getGJUsers20.php", authData, {
|
|
130
|
+
headers: headers
|
|
131
|
+
})
|
|
132
|
+
let authname;
|
|
133
|
+
if(auth.data == "-1") {
|
|
134
|
+
authname = "-"
|
|
135
|
+
} else if(!auth.data.startsWith("-")) {
|
|
136
|
+
authname = auth.data.split("1:")[1].split(":2:")[0];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { getSongInfo } = require("./getSongInfo.js");
|
|
140
|
+
const { getOfficialSongInfo } = require("./getOfficialSongInfo.js");
|
|
141
|
+
let song;
|
|
142
|
+
|
|
143
|
+
let copiedId = split19.split(":31:")[0];
|
|
144
|
+
if(copiedId.includes(":")) split19 = res.data.split(":30:")[2];
|
|
145
|
+
|
|
146
|
+
let starsCount = split6.split(":19:")[0];
|
|
147
|
+
if(starsCount.includes(":")) split6 = res.data.split(":18:")[2];
|
|
148
|
+
|
|
149
|
+
const decodeGameVersion = {
|
|
150
|
+
"1": "1.0",
|
|
151
|
+
"2": "1.1",
|
|
152
|
+
"3": "1.2",
|
|
153
|
+
"4": "1.3",
|
|
154
|
+
"5": "1.4",
|
|
155
|
+
"6": "1.5",
|
|
156
|
+
"7": "1.6",
|
|
157
|
+
"10": "1.7",
|
|
158
|
+
"18": "1.8",
|
|
159
|
+
"19": "1.9",
|
|
160
|
+
"20": "2.0",
|
|
161
|
+
"21": "2.1"
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let objs = split14.split(":15:")[0];
|
|
165
|
+
if(Number(objs) == NaN) objs = split14.split(":15:")[1];
|
|
166
|
+
|
|
167
|
+
let offSongID = Number(split25.split(":13:")[0]) + 1;
|
|
168
|
+
if(split25.split(":13:")[0] == "0" && split26.split(":36:")[0] != "0") {
|
|
169
|
+
try {
|
|
170
|
+
song = await getSongInfo(split26.split(":36:")[0]);
|
|
171
|
+
} catch(err) {
|
|
172
|
+
let songReq = await axios.post('http://www.boomlings.com/database/getGJLevels21.php', {
|
|
173
|
+
gameVersion: 21,
|
|
174
|
+
binaryVersion: 35,
|
|
175
|
+
gdw: 0,
|
|
176
|
+
type: 0,
|
|
177
|
+
str: level,
|
|
178
|
+
secret: "Wmfd2893gb7"
|
|
179
|
+
}, {
|
|
180
|
+
headers: headers
|
|
181
|
+
})
|
|
182
|
+
if(!songReq.data.includes("~|~")) {
|
|
183
|
+
song = {
|
|
184
|
+
"name": "Unknown",
|
|
185
|
+
"id": Number(split26.split(":36:")[0]),
|
|
186
|
+
"artist": "Unknown",
|
|
187
|
+
"artistId": null,
|
|
188
|
+
"fileSize": "0MB",
|
|
189
|
+
"link": null
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
song = {
|
|
193
|
+
"name": songReq.data.split("|~2~|~")[1].split("~|~3~|~")[0],
|
|
194
|
+
"id": Number(songReq.data.split("1~|~")[1].split("~|~2~|")[0]),
|
|
195
|
+
"artist": songReq.data.split("~|~4~|~")[1].split("~|~5~|~")[0],
|
|
196
|
+
"artistId": Number(songReq.data.split("~|~3~|~")[1].split("~|~4~|~")[0]),
|
|
197
|
+
"fileSize": `${songReq.data.split("~|~5~|~")[1].split("~|~6~|~")[0]} MB`,
|
|
198
|
+
"link": decodeURIComponent(songReq.data.split("~|~10~|~")[1].split("~|~7~|~")[0])
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} else if(split25.split(":13:")[0] != "0" && split26.split(":36:")[0] == "0") {
|
|
203
|
+
song = getOfficialSongInfo(offSongID);
|
|
204
|
+
} else if(split25.split(":13:")[0] == "0" && split26.split(":36:")[0] == "0") {
|
|
205
|
+
song = getOfficialSongInfo(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const result = {
|
|
209
|
+
"id": Number(split1.split(":2:")[0]),
|
|
210
|
+
"name": split2.split(":3:")[0].toString(),
|
|
211
|
+
"description": desc,
|
|
212
|
+
"creator": authname,
|
|
213
|
+
"level_version": Number(split4.split(":6:")[0]),
|
|
214
|
+
"difficulty": difficultyDecoding[split5.split(":10:")[0]].toString(),
|
|
215
|
+
"stars": Number(split6.split(":19:")[0]),
|
|
216
|
+
"downloads": Number(split7.split(":12:")[0]),
|
|
217
|
+
"likes": Number(likes),
|
|
218
|
+
"disliked": dislikedBool,
|
|
219
|
+
"length": lengthDecoding[split9.split(":30:")[0]],
|
|
220
|
+
"password": split10,
|
|
221
|
+
"demon": demonBool,
|
|
222
|
+
"featured": featured,
|
|
223
|
+
"epic": featuredDecoding[split13.split(":45:")[0]],
|
|
224
|
+
"objects": Number(objs),
|
|
225
|
+
"uploaded": split15.split(":29:")[0],
|
|
226
|
+
"updated": split16.split(":35:")[0],
|
|
227
|
+
"stars_requested": Number(split17.split(":46:")[0]),
|
|
228
|
+
"game_version": decodeGameVersion[split24.split(":14:")[0]],
|
|
229
|
+
"ldm": ldm,
|
|
230
|
+
"copied": Number(split19.split(":31:")[0]),
|
|
231
|
+
"two_p": binaryBool[split20.split(":28:")[0]],
|
|
232
|
+
"coins": Number(split21.split(":38:")[0]),
|
|
233
|
+
"verified_coins": binaryBool[split22.split(":39:")[0]],
|
|
234
|
+
"song": song
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
getLevelData:
|
|
3
|
+
function(level, log = false) {
|
|
4
|
+
if(typeof level === "string") throw new Error("The level parameter should be a number.");
|
|
5
|
+
const axios = require("axios");
|
|
6
|
+
const { headers } = require("../config.json");
|
|
7
|
+
|
|
8
|
+
const data = {
|
|
9
|
+
gameVersion: 21,
|
|
10
|
+
binaryVersion: 35,
|
|
11
|
+
gdw: 0,
|
|
12
|
+
levelID: level,
|
|
13
|
+
secret: "Wmfd2893gb7"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
axios.post('http://www.boomlings.com/database/downloadGJLevel22.php', data, {
|
|
17
|
+
headers: headers
|
|
18
|
+
|
|
19
|
+
}).then(res => {
|
|
20
|
+
|
|
21
|
+
if(res.data == -1) throw new Error("-1 Not found.")
|
|
22
|
+
if(res.data == "Error code: 1005") throw new Error("1005 error: Your IP address has been blocked from sending requests to a server. It's recommended to use locally (directly from a PC).")
|
|
23
|
+
|
|
24
|
+
let levelData = res.data.split(":4:")[1].split(":5:")[0]
|
|
25
|
+
if(log == true) console.log(levelData);
|
|
26
|
+
return levelData;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
getOfficialSongInfo:
|
|
3
|
+
function(song) {
|
|
4
|
+
if(isNaN(song)) throw new Error("A song id must be a number.")
|
|
5
|
+
const {
|
|
6
|
+
sm,
|
|
7
|
+
bot,
|
|
8
|
+
pg,
|
|
9
|
+
dout,
|
|
10
|
+
bab,
|
|
11
|
+
clg,
|
|
12
|
+
j,
|
|
13
|
+
tm,
|
|
14
|
+
c,
|
|
15
|
+
xs,
|
|
16
|
+
cf,
|
|
17
|
+
toe,
|
|
18
|
+
ea,
|
|
19
|
+
cs,
|
|
20
|
+
ed,
|
|
21
|
+
hf,
|
|
22
|
+
bp,
|
|
23
|
+
toeii,
|
|
24
|
+
gd,
|
|
25
|
+
d,
|
|
26
|
+
fd,
|
|
27
|
+
tss,
|
|
28
|
+
va,
|
|
29
|
+
ar,
|
|
30
|
+
tc,
|
|
31
|
+
p,
|
|
32
|
+
bm,
|
|
33
|
+
m,
|
|
34
|
+
y,
|
|
35
|
+
f,
|
|
36
|
+
sp,
|
|
37
|
+
s,
|
|
38
|
+
e,
|
|
39
|
+
round,
|
|
40
|
+
mdo,
|
|
41
|
+
ps,
|
|
42
|
+
ne,
|
|
43
|
+
pt,
|
|
44
|
+
unknown
|
|
45
|
+
} = require("../misc/officialsongs.json");
|
|
46
|
+
const jsons = {
|
|
47
|
+
1: sm,
|
|
48
|
+
2: bot,
|
|
49
|
+
3: pg,
|
|
50
|
+
4: dout,
|
|
51
|
+
5: bab,
|
|
52
|
+
6: clg,
|
|
53
|
+
7: j,
|
|
54
|
+
8: tm,
|
|
55
|
+
9: c,
|
|
56
|
+
10: xs,
|
|
57
|
+
11: cf,
|
|
58
|
+
12: toe,
|
|
59
|
+
13: ea,
|
|
60
|
+
14: cs,
|
|
61
|
+
15: ed,
|
|
62
|
+
16: hf,
|
|
63
|
+
17: bp,
|
|
64
|
+
18: toeii,
|
|
65
|
+
19: gd,
|
|
66
|
+
20: d,
|
|
67
|
+
21: fd,
|
|
68
|
+
22: tss,
|
|
69
|
+
23: va,
|
|
70
|
+
24: ar,
|
|
71
|
+
25: tc,
|
|
72
|
+
26: p,
|
|
73
|
+
27: bm,
|
|
74
|
+
28: m,
|
|
75
|
+
29: y,
|
|
76
|
+
30: f,
|
|
77
|
+
31: sp,
|
|
78
|
+
32: s,
|
|
79
|
+
33: e,
|
|
80
|
+
34: round,
|
|
81
|
+
35: mdo,
|
|
82
|
+
36: ps,
|
|
83
|
+
37: ne,
|
|
84
|
+
38: pt
|
|
85
|
+
}
|
|
86
|
+
let result = jsons[Number(song)];
|
|
87
|
+
if(result == undefined) result = unknown;
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
getSongInfo:
|
|
3
|
+
async function(song) {
|
|
4
|
+
if(isNaN(song)) throw new Error("A song id must be a number.")
|
|
5
|
+
const axios = require("axios")
|
|
6
|
+
const {headers} = require("../config.json")
|
|
7
|
+
|
|
8
|
+
const data = {
|
|
9
|
+
songID: song,
|
|
10
|
+
secret: "Wmfd2893gb7"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let res = await axios.post('http://www.boomlings.com/database/getGJSongInfo.php', data, {
|
|
14
|
+
headers: headers
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
if(res.data == -2) throw new Error(`-2. Couldn't find a song with ID ${song}.`)
|
|
18
|
+
if(res.data == "Error code: 1005") throw new Error("1005 error: Your IP address has been blocked from sending requests to a server. It's recommended to use locally (directly from a PC).")
|
|
19
|
+
|
|
20
|
+
const result = {
|
|
21
|
+
"name": res.data.split("|~2~|~")[1].split("~|~3~|~")[0],
|
|
22
|
+
"id": Number(res.data.split("1~|~")[1].split("~|~2~|")[0]),
|
|
23
|
+
"artist": res.data.split("~|~4~|~")[1].split("~|~5~|~")[0],
|
|
24
|
+
"artistId": Number(res.data.split("~|~3~|~")[1].split("~|~4~|~")[0]),
|
|
25
|
+
"fileSize": `${res.data.split("~|~5~|~")[1].split("~|~6~|~")[0]} MB`,
|
|
26
|
+
"link": decodeURIComponent(res.data.split("~|~10~|~")[1].split("~|~7~|~")[0])
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { dlLevel } = require("./functions/dlLevel.js");
|
|
2
|
+
const { getLevelData } = require("./functions/getLevelData.js");
|
|
3
|
+
const { getSongInfo } = require("./functions/getSongInfo.js");
|
|
4
|
+
const { getOfficialSongInfo } = require("./functions/getOfficialSongInfo.js");
|
|
5
|
+
const { decURLSafeBase64 } = require("./functions/decURLSafeBase64.js");
|
|
6
|
+
const { encURLSafeBase64 } = require("./functions/encURLSafeBase64.js");
|
|
7
|
+
|
|
8
|
+
module.exports.dlLevel = dlLevel;
|
|
9
|
+
module.exports.getLevelData = getLevelData;
|
|
10
|
+
module.exports.getSongInfo = getSongInfo;
|
|
11
|
+
module.exports.getOfficialSongInfo = getOfficialSongInfo;
|
|
12
|
+
module.exports.decURLSafeBase64 = decURLSafeBase64;
|
|
13
|
+
module.exports.encURLSafeBase64 = encURLSafeBase64;
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
{"sm": {
|
|
2
|
+
"name": "Stereo Madness",
|
|
3
|
+
"id": "Level 1",
|
|
4
|
+
"artist": "ForeverBound",
|
|
5
|
+
"fileSize": "0MB",
|
|
6
|
+
"link": "https://www.youtube.com/watch?v=JhKyKEDxo8Q"
|
|
7
|
+
},"bot": {
|
|
8
|
+
"name": "Back on Track",
|
|
9
|
+
"id": "Level 2",
|
|
10
|
+
"artist": "DJVI",
|
|
11
|
+
"fileSize": "0MB",
|
|
12
|
+
"link": "https://www.youtube.com/watch?v=N9vDTYZpqXM"
|
|
13
|
+
},
|
|
14
|
+
"pg": {
|
|
15
|
+
"name": "Polargeist",
|
|
16
|
+
"id": "Level 3",
|
|
17
|
+
"artist": "Step",
|
|
18
|
+
"fileSize": "0MB",
|
|
19
|
+
"link": "https://www.youtube.com/watch?v=4W28wWWxKuQ"
|
|
20
|
+
},
|
|
21
|
+
"dout": {
|
|
22
|
+
"name": "Dry Out",
|
|
23
|
+
"id": "Level 4",
|
|
24
|
+
"artist": "DJVI",
|
|
25
|
+
"fileSize": "0MB",
|
|
26
|
+
"link": "https://www.youtube.com/watch?v=FnXabH2q2A0"
|
|
27
|
+
},
|
|
28
|
+
"bab": {
|
|
29
|
+
"name": "Base After Base",
|
|
30
|
+
"id": "Level 5",
|
|
31
|
+
"artist": "DJVI",
|
|
32
|
+
"fileSize": "0MB",
|
|
33
|
+
"link": "https://www.youtube.com/watch?v=TZULkgQPHt0"
|
|
34
|
+
},
|
|
35
|
+
"clg": {
|
|
36
|
+
"name": "Cant Let Go",
|
|
37
|
+
"id": "Level 6",
|
|
38
|
+
"artist": "DJVI",
|
|
39
|
+
"fileSize": "0MB",
|
|
40
|
+
"link": "https://www.youtube.com/watch?v=fLnF-QnR1Zw"
|
|
41
|
+
},
|
|
42
|
+
"j": {
|
|
43
|
+
"name": "Jumper",
|
|
44
|
+
"id": "Level 7",
|
|
45
|
+
"artist": "Waterflame",
|
|
46
|
+
"fileSize": "0MB",
|
|
47
|
+
"link": "https://www.youtube.com/watch?v=ZXHO4AN_49Q"
|
|
48
|
+
},
|
|
49
|
+
"tm": {
|
|
50
|
+
"name": "Time Machine",
|
|
51
|
+
"id": "Level 8",
|
|
52
|
+
"artist": "Waterflame",
|
|
53
|
+
"fileSize": "0MB",
|
|
54
|
+
"link": "https://www.youtube.com/watch?v=zZ1L9JD6l0g"
|
|
55
|
+
},
|
|
56
|
+
"c": {
|
|
57
|
+
"name": "Cycles",
|
|
58
|
+
"id": "Level 9",
|
|
59
|
+
"artist": "DJVI",
|
|
60
|
+
"fileSize": "0MB",
|
|
61
|
+
"link": "https://www.youtube.com/watch?v=KDdvGZn6Gfs"
|
|
62
|
+
},
|
|
63
|
+
"xs": {
|
|
64
|
+
"name": "xStep",
|
|
65
|
+
"id": "Level 10",
|
|
66
|
+
"artist": "DJVI",
|
|
67
|
+
"fileSize": "0MB",
|
|
68
|
+
"link": "https://www.youtube.com/watch?v=PSvYfVGyQfw"
|
|
69
|
+
},
|
|
70
|
+
"cf": {
|
|
71
|
+
"name": "Clutterfunk",
|
|
72
|
+
"id": "Level 11",
|
|
73
|
+
"artist": "Waterflame",
|
|
74
|
+
"fileSize": "0MB",
|
|
75
|
+
"link": "https://www.youtube.com/watch?v=D5uJOpItgNg"
|
|
76
|
+
},
|
|
77
|
+
"toe": {
|
|
78
|
+
"name": "Theory of Everything",
|
|
79
|
+
"id": "Level 12",
|
|
80
|
+
"artist": "DJ-Nate",
|
|
81
|
+
"fileSize": "0MB",
|
|
82
|
+
"link": "https://www.newgrounds.com/audio/listen/354826"
|
|
83
|
+
},
|
|
84
|
+
"ea": {
|
|
85
|
+
"name": "Electroman Adventures",
|
|
86
|
+
"id": "Level 13",
|
|
87
|
+
"artist": "Waterflame",
|
|
88
|
+
"fileSize": "0MB",
|
|
89
|
+
"link": "https://www.youtube.com/watch?v=Pb6KyewC_Vg"
|
|
90
|
+
},
|
|
91
|
+
"cs": {
|
|
92
|
+
"name": "Clubstep",
|
|
93
|
+
"id": "Level 14",
|
|
94
|
+
"artist": "DJ-Nate",
|
|
95
|
+
"fileSize": "0MB",
|
|
96
|
+
"link": "https://www.newgrounds.com/audio/listen/396093"
|
|
97
|
+
},
|
|
98
|
+
"ed": {
|
|
99
|
+
"name": "Electrodynamix",
|
|
100
|
+
"id": "Level 15",
|
|
101
|
+
"artist": "DJ-Nate",
|
|
102
|
+
"fileSize": "0MB",
|
|
103
|
+
"link": "https://www.newgrounds.com/audio/listen/368392"
|
|
104
|
+
},
|
|
105
|
+
"hf": {
|
|
106
|
+
"name": "Hexagon Force",
|
|
107
|
+
"id": "Level 16",
|
|
108
|
+
"artist": "Waterflame",
|
|
109
|
+
"fileSize": "0MB",
|
|
110
|
+
"link": "https://www.youtube.com/watch?v=afwK743PL2Y"
|
|
111
|
+
},
|
|
112
|
+
"bp": {
|
|
113
|
+
"name": "Blast Processing",
|
|
114
|
+
"id": "Level 17",
|
|
115
|
+
"artist": "Waterflame",
|
|
116
|
+
"fileSize": "0MB",
|
|
117
|
+
"link": "https://www.youtube.com/watch?v=Z5RufkDHsdM"
|
|
118
|
+
},
|
|
119
|
+
"toeii": {
|
|
120
|
+
"name": "Theory of Everything 2",
|
|
121
|
+
"id": "Level 18",
|
|
122
|
+
"artist": "DJ-Nate",
|
|
123
|
+
"fileSize": "0MB",
|
|
124
|
+
"link": "https://www.newgrounds.com/audio/listen/790340"
|
|
125
|
+
},
|
|
126
|
+
"gd": {
|
|
127
|
+
"name": "Geometrical Dominator",
|
|
128
|
+
"id": "Level 19",
|
|
129
|
+
"artist": "Waterflame",
|
|
130
|
+
"fileSize": "0MB",
|
|
131
|
+
"link": "https://www.newgrounds.com/audio/listen/641172"
|
|
132
|
+
},
|
|
133
|
+
"d": {
|
|
134
|
+
"name": "Deadlocked",
|
|
135
|
+
"id": "Level 20",
|
|
136
|
+
"artist": "F-777",
|
|
137
|
+
"fileSize": "0MB",
|
|
138
|
+
"link": "https://www.youtube.com/watch?v=QRGkFkf2r0U"
|
|
139
|
+
},
|
|
140
|
+
"fd": {
|
|
141
|
+
"name": "Fingerdash",
|
|
142
|
+
"id": "Level 21",
|
|
143
|
+
"artist": "MDK",
|
|
144
|
+
"fileSize": "0MB",
|
|
145
|
+
"link": "https://www.youtube.com/watch?v=BuPmq7yjDnI"
|
|
146
|
+
},
|
|
147
|
+
"tss": {
|
|
148
|
+
"name": "The Seven Seas",
|
|
149
|
+
"id": "Level 1 (Geometry Dash: Meltdown)",
|
|
150
|
+
"artist": "F-777",
|
|
151
|
+
"fileSize": "0MB",
|
|
152
|
+
"link": "https://www.youtube.com/watch?v=38fPQ5JKQ_Q"
|
|
153
|
+
},
|
|
154
|
+
"va": {
|
|
155
|
+
"name": "Viking Arena",
|
|
156
|
+
"id": "Level 2 (Geometry Dash: Meltdown)",
|
|
157
|
+
"artist": "F-777",
|
|
158
|
+
"fileSize": "0MB",
|
|
159
|
+
"link": "https://www.youtube.com/watch?v=RaJ6Vf2w9hY"
|
|
160
|
+
},
|
|
161
|
+
"ar": {
|
|
162
|
+
"name": "Airborne Robots",
|
|
163
|
+
"id": "Level 3 (Geometry Dash: Meltdown)",
|
|
164
|
+
"artist": "F-777",
|
|
165
|
+
"fileSize": "0MB",
|
|
166
|
+
"link": "https://www.youtube.com/watch?v=guBpnPY32s0"
|
|
167
|
+
},
|
|
168
|
+
"tc": {
|
|
169
|
+
"name": "Random Song 06",
|
|
170
|
+
"id": "Level 22 (The Challenge)",
|
|
171
|
+
"artist": "RobTop",
|
|
172
|
+
"fileSize": "0MB",
|
|
173
|
+
"link": "https://www.newgrounds.com/audio/listen/633385"
|
|
174
|
+
},
|
|
175
|
+
"p": {
|
|
176
|
+
"name": "Payload",
|
|
177
|
+
"id": "Level 1 (Geometry Dash: World)",
|
|
178
|
+
"artist": "Dex Arson",
|
|
179
|
+
"fileSize": "0MB",
|
|
180
|
+
"link": "https://www.youtube.com/watch?v=2SFOjJxEL7g"
|
|
181
|
+
},
|
|
182
|
+
"bm": {
|
|
183
|
+
"name": "Beast Mode",
|
|
184
|
+
"id": "Level 2 (Geometry Dash: World)",
|
|
185
|
+
"artist": "Dex Arson",
|
|
186
|
+
"fileSize": "0MB",
|
|
187
|
+
"link": "https://www.newgrounds.com/audio/listen/589874"
|
|
188
|
+
},
|
|
189
|
+
"m": {
|
|
190
|
+
"name": "Machina",
|
|
191
|
+
"id": "Level 3 (Geometry Dash: World)",
|
|
192
|
+
"artist": "Dex Arson",
|
|
193
|
+
"fileSize": "0MB",
|
|
194
|
+
"link": "https://www.youtube.com/watch?v=EWjZOxs87yg"
|
|
195
|
+
},
|
|
196
|
+
"y": {
|
|
197
|
+
"name": "Years",
|
|
198
|
+
"id": "Level 4 (Geometry Dash: World)",
|
|
199
|
+
"artist": "Dex Arson",
|
|
200
|
+
"fileSize": "0MB",
|
|
201
|
+
"link": "https://www.youtube.com/watch?v=0MZvDD_sy-w"
|
|
202
|
+
},
|
|
203
|
+
"f": {
|
|
204
|
+
"name": "Frontlines",
|
|
205
|
+
"id": "Level 5 (Geometry Dash: World)",
|
|
206
|
+
"artist": "Dex Arson",
|
|
207
|
+
"fileSize": "0MB",
|
|
208
|
+
"link": "https://www.youtube.com/watch?v=f3wAripOdag"
|
|
209
|
+
},
|
|
210
|
+
"sp": {
|
|
211
|
+
"name": "Space Pirates",
|
|
212
|
+
"id": "Level 6 (Geometry Dash: World)",
|
|
213
|
+
"artist": "Waterflame",
|
|
214
|
+
"fileSize": "0MB",
|
|
215
|
+
"link": "https://www.youtube.com/watch?v=Cu7HaeRHMhM"
|
|
216
|
+
},
|
|
217
|
+
"s": {
|
|
218
|
+
"name": "Striker",
|
|
219
|
+
"id": "Level 7 (Geometry Dash: World)",
|
|
220
|
+
"artist": "Waterflame",
|
|
221
|
+
"fileSize": "0MB",
|
|
222
|
+
"link": "https://www.youtube.com/watch?v=MU9wRCGt9h8"
|
|
223
|
+
},
|
|
224
|
+
"e": {
|
|
225
|
+
"name": "Embers",
|
|
226
|
+
"id": "Level 8 (Geometry Dash: World)",
|
|
227
|
+
"artist": "Dex Arson",
|
|
228
|
+
"fileSize": "0MB",
|
|
229
|
+
"link": "https://www.youtube.com/watch?v=nMDMlIvdqlA"
|
|
230
|
+
},
|
|
231
|
+
"round": {
|
|
232
|
+
"name": "Round 1",
|
|
233
|
+
"id": "Level 9 (Geometry Dash: World)",
|
|
234
|
+
"artist": "Dex Arson",
|
|
235
|
+
"fileSize": "0MB",
|
|
236
|
+
"link": "https://www.youtube.com/watch?v=NvQoY4gTIGU"
|
|
237
|
+
},
|
|
238
|
+
"mdo": {
|
|
239
|
+
"name": "Monster Dance Off",
|
|
240
|
+
"id": "Level 10 (Geometry Dash: World)",
|
|
241
|
+
"artist": "F-777",
|
|
242
|
+
"fileSize": "0MB",
|
|
243
|
+
"link": "https://www.youtube.com/watch?v=B8YkwDbGBr8"
|
|
244
|
+
},
|
|
245
|
+
"ps": {
|
|
246
|
+
"name": "Press Start",
|
|
247
|
+
"id": "Level 1 (Geometry Dash: SubZero)",
|
|
248
|
+
"artist": "MDK",
|
|
249
|
+
"fileSize": "0MB",
|
|
250
|
+
"link": "https://www.youtube.com/watch?v=XoLouT7TqZY"
|
|
251
|
+
},
|
|
252
|
+
"ne": {
|
|
253
|
+
"name": "Nock Em",
|
|
254
|
+
"id": "Level 2 (Geometry Dash: SubZero)",
|
|
255
|
+
"artist": "Bossfight",
|
|
256
|
+
"fileSize": "0MB",
|
|
257
|
+
"link": "https://www.youtube.com/watch?v=ePv2X_CCaGg"
|
|
258
|
+
},
|
|
259
|
+
"pt": {
|
|
260
|
+
"name": "Power Trip",
|
|
261
|
+
"id": "Level 3 (Geometry Dash: SubZero)",
|
|
262
|
+
"artist": "Boom Kitty",
|
|
263
|
+
"fileSize": "0MB",
|
|
264
|
+
"link": "https://www.youtube.com/watch?v=l6OsF7RlQb4"
|
|
265
|
+
},
|
|
266
|
+
"unknown": {
|
|
267
|
+
"name": "Unknown",
|
|
268
|
+
"id": "This song is not defined by RobTop. In game it returns \"Back on Track\".",
|
|
269
|
+
"artist": "DJVI",
|
|
270
|
+
"fileSize": "0MB",
|
|
271
|
+
"link": null
|
|
272
|
+
}
|
|
273
|
+
}
|
package/misc/xor.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
module.exports = class XOR {
|
|
2
|
+
xor(str, key) { return String.fromCodePoint(...str.split('').map((char, i) => char.charCodeAt(0) ^ key.toString().charCodeAt(i % key.toString().length))) }
|
|
3
|
+
encrypt(str, key = 37526) { return Buffer.from(this.xor(str, key)).toString('base64').replace(/\//g, '_').replace(/\+/g, '-'); }
|
|
4
|
+
decrypt(str, key = 37526) { return this.xor(Buffer.from(str.replace(/\//g, '_').replace(/\+/g, '-'), 'base64').toString(), key) }
|
|
5
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gj-boomlings-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A Node.js module that allows you to fetch boomlings.com easily",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"start": "node ."
|
|
9
|
+
},
|
|
10
|
+
"author": "shikoshib",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/shikoshib/gj-boomlings-api.git"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/shikoshib/gj-boomlings-api/issues"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/shikoshib/gj-boomlings-api",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"axios": "^1.2.1",
|
|
22
|
+
"crypto": "^1.0.1",
|
|
23
|
+
"js-base64": "^3.7.3",
|
|
24
|
+
"node-fetch": "^2.6.7",
|
|
25
|
+
"xor-crypt": "^1.1.1"
|
|
26
|
+
}
|
|
27
|
+
}
|