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 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,9 @@
1
+ module.exports = {
2
+ encURLSafeBase64:
3
+ function(string) {
4
+ const bs = require("js-base64");
5
+ if(!string) throw new Error("No string provided!")
6
+ let str = bs.encode(string).replace('/', /_/g).replace('+', /-/g);
7
+ return str;
8
+ }
9
+ }
@@ -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
+ }