gj-boomlings-api 0.3.0 → 0.5.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 +19 -3
- package/docs/getAccountPosts.md +71 -0
- package/docs/getCommentHistory.md +2 -0
- package/docs/getComments.md +2 -0
- package/docs/getGauntlets.md +2 -1
- package/docs/getMapPacks.md +88 -0
- package/docs/objects/acc_comment.md +19 -0
- package/docs/objects/comment.md +7 -0
- package/docs/objects/level.md +25 -0
- package/docs/objects/song.md +5 -0
- package/docs/objects/user.md +16 -0
- package/docs/uploadAccountPost.md +27 -0
- package/docs/uploadComment.md +28 -0
- package/functions/encURLSafeBase64.js +1 -1
- package/functions/getAccountPosts.js +147 -0
- package/functions/getMapPacks.js +39 -0
- package/functions/getProfile.js +3 -2
- package/functions/uploadAccountPost.js +53 -0
- package/functions/uploadComment.js +64 -0
- package/index.js +9 -1
- package/misc/decodeAccountPost.js +18 -0
- package/misc/decodeMapPack.js +55 -0
- package/misc/gjp.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://www.npmjs.com/package/gj-boomlings-api"><img src="https://shikoshib.github.io/font1.png" width="600"></a><hr>
|
|
3
|
+
<a href="https://www.npmjs.com/package/gj-boomlings-api"><img src="https://img.shields.io/npm/v/gj-boomlings-api.svg?maxAge=3600" alt="npm version" /></a>
|
|
4
|
+
<a href="https://www.npmjs.com/package/gj-boomlings-api"><img src="https://img.shields.io/npm/dt/gj-boomlings-api.svg?maxAge=3600" alt="npm downloads" /></a>
|
|
5
|
+
<a href="https://snyk.io/test/github/shikoshib/gj-boomlings-api"><img src="https://snyk.io/test/github/shikoshib/gj-boomlings-api/badge.svg" alt="Known Vulnerabilities" /></a>
|
|
6
|
+
</div>
|
|
2
7
|
|
|
3
8
|
This package gets info from RobTop's servers (boomlings.com) and converts it into pure and beautiful JSON.
|
|
4
9
|
|
|
@@ -52,7 +57,6 @@ Returns:
|
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
```
|
|
55
|
-
|
|
56
60
|
### getProfile(user)
|
|
57
61
|
|
|
58
62
|
With this function, you can get somebody's profile info. You can use a player ID (not the account ID) or a name string, it doesn't matter.
|
|
@@ -85,8 +89,20 @@ Returns:
|
|
|
85
89
|
twitch: 'https://twitch.tv/robtopgames'
|
|
86
90
|
}
|
|
87
91
|
```
|
|
92
|
+
### uploadComment(comment, id, user, password, percent)
|
|
93
|
+
|
|
94
|
+
You can post comments with this function.
|
|
95
|
+
|
|
96
|
+
For example,
|
|
97
|
+
```js
|
|
98
|
+
const gd = require("gj-boomlings-api");
|
|
99
|
+
gd.uploadComment("I love gj-boomlings-api!", 83925274, "gmdshxdow", "*********", 99).then(console.log);
|
|
100
|
+
// of course you need to replace the asterisks with your password
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Posts a comment on the level with the ID of 83925274, with 99 percent, on gmdshxdow's behalf.
|
|
88
104
|
|
|
89
|
-
Check out [docs](./docs/) for more info
|
|
105
|
+
**Check out [docs](./docs/) for more info.**
|
|
90
106
|
|
|
91
107
|
---
|
|
92
108
|
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# getAccountPosts()
|
|
2
|
+
|
|
3
|
+
Gets the account comments from someone's profile.
|
|
4
|
+
|
|
5
|
+
## Parameters
|
|
6
|
+
`user` - the username or player ID.
|
|
7
|
+
|
|
8
|
+
`page` (optional) - the page of the posts. Defaults to 1.
|
|
9
|
+
|
|
10
|
+
## Example
|
|
11
|
+
```js
|
|
12
|
+
const gd = require("gj-boomlings-api");
|
|
13
|
+
gd.getAccountPosts("robtop").then(console.log);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Response
|
|
17
|
+
```js
|
|
18
|
+
[
|
|
19
|
+
{
|
|
20
|
+
content: "Thank you everyone for the birthday wishes. You're the best! :)",
|
|
21
|
+
likes: 97911,
|
|
22
|
+
age: '10 months'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
content: 'Happy New Year everyone! :D',
|
|
26
|
+
likes: 60720,
|
|
27
|
+
age: '11 months'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
content: 'Thank you all for the birthday wishes :)',
|
|
31
|
+
likes: 144296,
|
|
32
|
+
age: '1 year'
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
content: 'Happy New Year everyone!... Still should post more often xD',
|
|
36
|
+
likes: 86611,
|
|
37
|
+
age: '1 year'
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
content: 'Happy New Year everyone!... I should really post more often than this xD',
|
|
41
|
+
likes: 133553,
|
|
42
|
+
age: '2 years'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
content: 'Happy New Year everyone! :D',
|
|
46
|
+
likes: 272323,
|
|
47
|
+
age: '3 years'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
content: 'Its amazing how talented level creators are these days :)',
|
|
51
|
+
likes: 259426,
|
|
52
|
+
age: '5 years'
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
content: 'El pollo ardiente...',
|
|
56
|
+
likes: 240085,
|
|
57
|
+
age: '5 years'
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
content: 'I am eating an apple.',
|
|
61
|
+
likes: 222661,
|
|
62
|
+
age: '5 years'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
content: 'RubRubRubRubRubRubRubRubRubRubRubRubRubRubRubRubRubRub',
|
|
66
|
+
likes: 241988,
|
|
67
|
+
age: '5 years'
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
```
|
|
71
|
+
Returns an array of [account comments](./objects/acc_comment.md).
|
|
@@ -4,7 +4,9 @@ Gets a comment history from a specified player.
|
|
|
4
4
|
|
|
5
5
|
## Parameters
|
|
6
6
|
`user` - the player's username or a player ID.
|
|
7
|
+
|
|
7
8
|
`page` (optional) - the page of the comment history. Defaults to 1.
|
|
9
|
+
|
|
8
10
|
`mode` (optional) - the mode of fetching the comment history. `1` is the most liked and `0` is the most recent. Defaults to 1.
|
|
9
11
|
|
|
10
12
|
## Example
|
package/docs/getComments.md
CHANGED
|
@@ -4,7 +4,9 @@ Gets a list of comments from a specified level.
|
|
|
4
4
|
|
|
5
5
|
## Parameters
|
|
6
6
|
`level` - the level whose comments we want to check.
|
|
7
|
+
|
|
7
8
|
`page` (optional) - the page of the comments. Defaults to 1.
|
|
9
|
+
|
|
8
10
|
`mode` (optional) - the mode of fetching the comments. `1` is the most liked and `0` is the most recent. Defaults to 1.
|
|
9
11
|
|
|
10
12
|
## Example
|
package/docs/getGauntlets.md
CHANGED
|
@@ -73,8 +73,9 @@ gd.getGauntlets().then(console.log);
|
|
|
73
73
|
}
|
|
74
74
|
]
|
|
75
75
|
```
|
|
76
|
-
This function returns an array of
|
|
76
|
+
This function returns an array of gauntlet objects.
|
|
77
77
|
|
|
78
78
|
### Properties
|
|
79
79
|
`name` - the gauntlet name.
|
|
80
|
+
|
|
80
81
|
`levels` - the array of levels in a gauntlet.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# getMapPacks()
|
|
2
|
+
|
|
3
|
+
Gets the list of map packs and decodes it.
|
|
4
|
+
|
|
5
|
+
## Parameters
|
|
6
|
+
`page` (optional) - the page of the map packs list. Defaults to 1.
|
|
7
|
+
|
|
8
|
+
## Example
|
|
9
|
+
```js
|
|
10
|
+
const gd = require("gj-boomlings-api");
|
|
11
|
+
gd.getMapPacks(2).then(console.log);
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Response
|
|
15
|
+
```
|
|
16
|
+
[
|
|
17
|
+
{
|
|
18
|
+
name: 'Ruby Pack',
|
|
19
|
+
levels: [ 1446958, 1063115, 1734354 ],
|
|
20
|
+
stars: 4,
|
|
21
|
+
coins: 1
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Electro Pack',
|
|
25
|
+
levels: [ 5131543, 8157377, 8571598 ],
|
|
26
|
+
stars: 4,
|
|
27
|
+
coins: 1
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'Laser Pack',
|
|
31
|
+
levels: [ 12178580, 11357573, 11591917 ],
|
|
32
|
+
stars: 4,
|
|
33
|
+
coins: 1
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'Glow Pack',
|
|
37
|
+
levels: [ 4449079, 6979485, 10110092 ],
|
|
38
|
+
stars: 4,
|
|
39
|
+
coins: 1
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Spirit Pack',
|
|
43
|
+
levels: [ 13766381, 13242284, 13963465 ],
|
|
44
|
+
stars: 4,
|
|
45
|
+
coins: 1
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Hard Pack',
|
|
49
|
+
levels: [ 217631, 3785, 281148 ],
|
|
50
|
+
stars: 5,
|
|
51
|
+
coins: 1
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'Morph Pack',
|
|
55
|
+
levels: [ 364445, 411459, 509393 ],
|
|
56
|
+
stars: 5,
|
|
57
|
+
coins: 1
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Phoenix Pack',
|
|
61
|
+
levels: [ 674454, 750434, 835854 ],
|
|
62
|
+
stars: 5,
|
|
63
|
+
coins: 1
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'Power Pack',
|
|
67
|
+
levels: [ 809579, 741941, 577710 ],
|
|
68
|
+
stars: 5,
|
|
69
|
+
coins: 1
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Shiny Pack',
|
|
73
|
+
levels: [ 980341, 1541962, 1160937 ],
|
|
74
|
+
stars: 5,
|
|
75
|
+
coins: 1
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
```
|
|
79
|
+
This function returns an array of map pack objects.
|
|
80
|
+
|
|
81
|
+
### Properties
|
|
82
|
+
`name` - the map pack name.
|
|
83
|
+
|
|
84
|
+
`levels` - the array of levels in a map pack.
|
|
85
|
+
|
|
86
|
+
`stars` - the amount of stars you get from beating the map pack.
|
|
87
|
+
|
|
88
|
+
`coins` - the amount of coins you get from beating the map pack.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Account comment object
|
|
2
|
+
|
|
3
|
+
Used by `getAccountPosts()`.
|
|
4
|
+
|
|
5
|
+
## Example
|
|
6
|
+
```
|
|
7
|
+
{
|
|
8
|
+
content: "Thank you everyone for the birthday wishes. You're the best! :)",
|
|
9
|
+
likes: 97911,
|
|
10
|
+
age: '10 months'
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Properties
|
|
15
|
+
```content``` - the actual content of a comment.
|
|
16
|
+
|
|
17
|
+
```likes``` - the amount of likes on a comment.
|
|
18
|
+
|
|
19
|
+
```age``` - the age of a comment.
|
package/docs/objects/comment.md
CHANGED
|
@@ -18,10 +18,17 @@ Used by `getComments()` and `getCommentHistory()`.
|
|
|
18
18
|
|
|
19
19
|
## Properties
|
|
20
20
|
```username``` - the comment author's username.
|
|
21
|
+
|
|
21
22
|
```content``` - the actual content of a comment.
|
|
23
|
+
|
|
22
24
|
```levelID``` - the ID of a level, on which the comment was sent.
|
|
25
|
+
|
|
23
26
|
```playerID``` - the comment author's player ID.
|
|
27
|
+
|
|
24
28
|
```likes``` - the amount of likes on a comment.
|
|
29
|
+
|
|
25
30
|
```percent``` - the percentage that has been put on this comment. Returns `0` if the percentage checkbox hadn't been checked.
|
|
31
|
+
|
|
26
32
|
```id``` - the ID of a comment.
|
|
33
|
+
|
|
27
34
|
```age``` - the age of a comment.
|
package/docs/objects/level.md
CHANGED
|
@@ -43,28 +43,53 @@ Used by ```dlLevel()```.
|
|
|
43
43
|
|
|
44
44
|
## Properties
|
|
45
45
|
```id``` - the level ID.
|
|
46
|
+
|
|
46
47
|
```name``` - the level name.
|
|
48
|
+
|
|
47
49
|
```description``` - the level description.
|
|
50
|
+
|
|
48
51
|
```creator``` - the level creator.
|
|
52
|
+
|
|
49
53
|
```level_version``` - the version of a level.
|
|
54
|
+
|
|
50
55
|
```difficulty``` - the level difficulty.
|
|
56
|
+
|
|
51
57
|
```stars``` - the amount of stars you get from beating the level.
|
|
58
|
+
|
|
52
59
|
```downloads``` - the amount of level downloads.
|
|
60
|
+
|
|
53
61
|
```likes``` - the amount of level likes.
|
|
62
|
+
|
|
54
63
|
```disliked``` - a boolean that shows if the level is disliked. Returns ```true``` if the like amount is negative, otherwise it's ```false```.
|
|
64
|
+
|
|
55
65
|
```length``` - the level length.
|
|
66
|
+
|
|
56
67
|
```password``` - the level password. It may return ```'Non-copyable'``` if the level is not copyable, or ```'1'``` if the level is free to copy.
|
|
68
|
+
|
|
57
69
|
```demon``` - a boolean that shows if the level is demon.
|
|
70
|
+
|
|
58
71
|
```featured``` - a boolean that shows if the level has been featured.
|
|
72
|
+
|
|
59
73
|
```epic``` - a boolean that shows if the level is epic-rated.
|
|
74
|
+
|
|
60
75
|
```objects``` - the amount of level objects. However, this property has a cap of 65535 objects (it's RobTop's problem).
|
|
76
|
+
|
|
61
77
|
```uploaded``` - when the level has been uploaded.
|
|
78
|
+
|
|
62
79
|
```updated``` - when the level has been last updated.
|
|
80
|
+
|
|
63
81
|
```stars_requested``` - basically how many stars the creator has requested. Returns ```0``` if no stars have been requested.
|
|
82
|
+
|
|
64
83
|
```game_version``` - the version required to play the level.
|
|
84
|
+
|
|
65
85
|
```ldm``` - a boolean that shows if the level has a "Low Detail Mode" checkbox.
|
|
86
|
+
|
|
66
87
|
```copied``` - the original level ID, that got copied. Returns ```0``` if the level is already original.
|
|
88
|
+
|
|
67
89
|
```two_p``` - a boolean that shows if the level is in the 2-player mode.
|
|
90
|
+
|
|
68
91
|
```coins``` - the amount of coins in the level.
|
|
92
|
+
|
|
69
93
|
```verified_coins``` - a boolean that shows if the coins are verified (silver coins).
|
|
94
|
+
|
|
70
95
|
```song``` - a [song object](./song.md).
|
package/docs/objects/song.md
CHANGED
|
@@ -16,8 +16,13 @@ Used by `getOfficialSongInfo()` and `getSongInfo()`.
|
|
|
16
16
|
|
|
17
17
|
## Properties
|
|
18
18
|
```name``` - the song name.
|
|
19
|
+
|
|
19
20
|
```id``` - the song ID.
|
|
21
|
+
|
|
20
22
|
```artist``` - the song artist.
|
|
23
|
+
|
|
21
24
|
```artistId``` - the artist's Newgrounds ID.
|
|
25
|
+
|
|
22
26
|
```fileSize``` - the size of the song in megabytes, rounded to two decimals.
|
|
27
|
+
|
|
23
28
|
```link``` - the link to a file of the song.
|
package/docs/objects/user.md
CHANGED
|
@@ -27,19 +27,35 @@ Used by ```getProfile()```.
|
|
|
27
27
|
|
|
28
28
|
## Properties
|
|
29
29
|
```username``` - the player's username.
|
|
30
|
+
|
|
30
31
|
```playerID``` - the player ID.
|
|
32
|
+
|
|
31
33
|
```accountID``` - the account ID.
|
|
34
|
+
|
|
32
35
|
```rank``` - the user's position in the global leaderboard. Returns `0` if the player hasn't received it yet or if the player is banned on the leaderboard.
|
|
36
|
+
|
|
33
37
|
```stars``` - the amount of stars the player has.
|
|
38
|
+
|
|
34
39
|
```diamonds``` - the amount of diamonds the player has.
|
|
40
|
+
|
|
35
41
|
```secretCoins``` - the amount of secret (gold) coins the player has collected.
|
|
42
|
+
|
|
36
43
|
```userCoins``` - the amount of user (white) coins the player has collected.
|
|
44
|
+
|
|
37
45
|
```demons``` - the amount of demons the player has beaten.
|
|
46
|
+
|
|
38
47
|
```creatorPoints``` - the amount of creator points the player has.
|
|
48
|
+
|
|
39
49
|
```messages``` - a property that shows if you can send messages to the player. Returns `"none"` if the DMs are closed, `"friends"` if sending DMs is available to only friends, and `"all"` if everyone can send messages to the specified player.
|
|
50
|
+
|
|
40
51
|
```friendRequests``` - a property that shows if you can send friend requests to the player. Returns `"none"` if you can't or `"all"` if everyone can send friend requests to the specified player.
|
|
52
|
+
|
|
41
53
|
```commentHistory``` - a property that shows if you can view the player's comment history. Returns `"none"` if you can't, `"friends"` if viewing the comment history is available to only friends, and `"all"` if everyone can view the comment history.
|
|
54
|
+
|
|
42
55
|
```mod``` - a property that shows if the player is an in-game moderator. Returns `"none"` if not, `"mod"` if the player is a regular Mod (yellow badge), and `"elder"` if the player is an Elder Mod (orange badge).
|
|
56
|
+
|
|
43
57
|
```youtube``` - the link to the player's YouTube channel.
|
|
58
|
+
|
|
44
59
|
```twitter``` - the link to the player's Twitter account.
|
|
60
|
+
|
|
45
61
|
```twitch``` - the link to the player's Twitch channel.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# uploadAccountPost()
|
|
2
|
+
|
|
3
|
+
Posts a comment to a profile.
|
|
4
|
+
|
|
5
|
+
## Parameters
|
|
6
|
+
`content` - the actual comment content.
|
|
7
|
+
|
|
8
|
+
`user` - the username or player ID.
|
|
9
|
+
|
|
10
|
+
`gjp` - the user's password.
|
|
11
|
+
|
|
12
|
+
## Example
|
|
13
|
+
```js
|
|
14
|
+
const gd = require("gj-boomlings-api");
|
|
15
|
+
gd.uploadAccountPost("I love gj-boomlings-api!", "gmdshxdow", "*********").then(console.log);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Response
|
|
19
|
+
```js
|
|
20
|
+
1
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Returns `1` if the comment was successfully posted.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Fun fact: you can actually post comments with non-Latin characters (Cyrillic letters, Arabic letters, etc.), but I don't recommend you to use them, cuz they are often really buggy.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# uploadComment()
|
|
2
|
+
|
|
3
|
+
Posts a comment to a profile.
|
|
4
|
+
|
|
5
|
+
## Parameters
|
|
6
|
+
|
|
7
|
+
`content` - the actual comment content.
|
|
8
|
+
|
|
9
|
+
`id` - the level ID.
|
|
10
|
+
|
|
11
|
+
`user` - the username or player ID.
|
|
12
|
+
|
|
13
|
+
`gjp` - the user's password
|
|
14
|
+
|
|
15
|
+
`percent` (optional) - the comment percentage. Defaults to 0.
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
```js
|
|
19
|
+
const gd = require("gj-boomlings-api");
|
|
20
|
+
gd.uploadComment("I love gj-boomlings-api!", 83925274, "gmdshxdow", "*********", 99).then(console.log);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Response
|
|
24
|
+
```js
|
|
25
|
+
1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Returns `1` if the comment was successfully posted.
|
|
@@ -3,7 +3,7 @@ module.exports = {
|
|
|
3
3
|
function(string) {
|
|
4
4
|
const bs = require("js-base64");
|
|
5
5
|
if(!string || string == "") throw new Error("No string provided!")
|
|
6
|
-
let str = bs.encode(string,
|
|
6
|
+
let str = bs.encode(string).replace(/\//g, '_').replace(/w+/g, '-');
|
|
7
7
|
return str;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
getAccountPosts:
|
|
3
|
+
async function(str, page = 1) {
|
|
4
|
+
if(!str || str == "") throw new Error("Please provide a user ID or name!");
|
|
5
|
+
const { decodeAccountPost } = require("../misc/decodeAccountPost.js");
|
|
6
|
+
const axios = require("axios");
|
|
7
|
+
const { headers, server } = require("../config.json");
|
|
8
|
+
|
|
9
|
+
const data = {
|
|
10
|
+
gameVersion: 21,
|
|
11
|
+
binaryVersion: 35,
|
|
12
|
+
gdw: 0,
|
|
13
|
+
str: str,
|
|
14
|
+
secret: "Wmfd2893gb7"
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let r = await axios.post(server + "getGJUsers20.php", data, {
|
|
18
|
+
headers: headers
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
if(r.data == -1) throw new Error("-1 This user is not found.")
|
|
22
|
+
let id = r.data.split(":16:")[1].split(":3:")[0];
|
|
23
|
+
if(Number(id) < 71 || id.includes(":")) id = r.data.split(":16:")[2].split(":3:")[0];
|
|
24
|
+
|
|
25
|
+
let ACdata = {
|
|
26
|
+
gameVersion: 21,
|
|
27
|
+
binaryVersion: 35,
|
|
28
|
+
gdw: 0,
|
|
29
|
+
accountID: id,
|
|
30
|
+
secret: "Wmfd2893gb7",
|
|
31
|
+
page: page - 1
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
let res = await axios.post(server + "getGJAccountComments20.php", ACdata, {
|
|
35
|
+
headers: headers
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if(res.data == -1) throw new Error("-1 Not found.")
|
|
39
|
+
if(res.data.toLowerCase() == "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).")
|
|
40
|
+
if(res.data.startsWith("#")) throw new Error("Whoops! Couldn't find anything!");
|
|
41
|
+
|
|
42
|
+
let firstPost = res.data;
|
|
43
|
+
let secondPost;
|
|
44
|
+
let thirdPost;
|
|
45
|
+
let fourthPost;
|
|
46
|
+
let fifthPost;
|
|
47
|
+
let sixthPost;
|
|
48
|
+
let seventhPost;
|
|
49
|
+
let eighthPost;
|
|
50
|
+
let ninthPost;
|
|
51
|
+
let tenthPost;
|
|
52
|
+
|
|
53
|
+
let result = [decodeAccountPost(firstPost)]
|
|
54
|
+
|
|
55
|
+
if(res.data.split("|").length - 1 == 1) {
|
|
56
|
+
firstPost = res.data.split("|")[0];
|
|
57
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
58
|
+
result.push(decodeAccountPost(secondPost))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if(res.data.split("|").length - 1 == 2) {
|
|
62
|
+
firstPost = res.data.split("|")[0];
|
|
63
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
64
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
65
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost))
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if(res.data.split("|").length - 1 == 3) {
|
|
69
|
+
firstPost = res.data.split("|")[0];
|
|
70
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
71
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
72
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
73
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if(res.data.split("|").length - 1 == 4) {
|
|
77
|
+
firstPost = res.data.split("|")[0];
|
|
78
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
79
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
80
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
81
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
82
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if(res.data.split("|").length - 1 == 5) {
|
|
86
|
+
firstPost = res.data.split("|")[0];
|
|
87
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
88
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
89
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
90
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
91
|
+
sixthPost = res.data.split("|")[5].split("|")[0];
|
|
92
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost),decodeAccountPost(sixthPost))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if(res.data.split("|").length - 1 == 6) {
|
|
96
|
+
firstPost = res.data.split("|")[0];
|
|
97
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
98
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
99
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
100
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
101
|
+
sixthPost = res.data.split("|")[5].split("|")[0];
|
|
102
|
+
seventhPost = res.data.split("|")[6].split("|")[0];
|
|
103
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost),decodeAccountPost(sixthPost),decodeAccountPost(seventhPost))
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if(res.data.split("|").length - 1 == 7) {
|
|
107
|
+
firstPost = res.data.split("|")[0];
|
|
108
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
109
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
110
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
111
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
112
|
+
sixthPost = res.data.split("|")[5].split("|")[0];
|
|
113
|
+
seventhPost = res.data.split("|")[6].split("|")[0];
|
|
114
|
+
eighthPost = res.data.split("|")[7].split("|")[0];
|
|
115
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost),decodeAccountPost(sixthPost),decodeAccountPost(seventhPost),decodeAccountPost(eighthPost))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if(res.data.split("|").length - 1 == 8) {
|
|
119
|
+
firstPost = res.data.split("|")[0];
|
|
120
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
121
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
122
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
123
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
124
|
+
sixthPost = res.data.split("|")[5].split("|")[0];
|
|
125
|
+
seventhPost = res.data.split("|")[6].split("|")[0];
|
|
126
|
+
eighthPost = res.data.split("|")[7].split("|")[0];
|
|
127
|
+
ninthPost = res.data.split("|")[8].split("|")[0];
|
|
128
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost),decodeAccountPost(sixthPost),decodeAccountPost(seventhPost),decodeAccountPost(eighthPost),decodeAccountPost(ninthPost))
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if(res.data.split("|").length - 1 == 9) {
|
|
132
|
+
firstPost = res.data.split("|")[0];
|
|
133
|
+
secondPost = res.data.split("|")[1].split("|")[0];
|
|
134
|
+
thirdPost = res.data.split("|")[2].split("|")[0];
|
|
135
|
+
fourthPost = res.data.split("|")[3].split("|")[0];
|
|
136
|
+
fifthPost = res.data.split("|")[4].split("|")[0];
|
|
137
|
+
sixthPost = res.data.split("|")[5].split("|")[0];
|
|
138
|
+
seventhPost = res.data.split("|")[6].split("|")[0];
|
|
139
|
+
eighthPost = res.data.split("|")[7].split("|")[0];
|
|
140
|
+
ninthPost = res.data.split("|")[8].split("|")[0];
|
|
141
|
+
tenthPost = res.data.split("|")[9].split("|")[0];
|
|
142
|
+
result.push(decodeAccountPost(secondPost),decodeAccountPost(thirdPost),decodeAccountPost(fourthPost),decodeAccountPost(fifthPost),decodeAccountPost(sixthPost),decodeAccountPost(seventhPost),decodeAccountPost(eighthPost),decodeAccountPost(ninthPost),decodeAccountPost(tenthPost))
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
getMapPacks:
|
|
3
|
+
async function(page = 1) {
|
|
4
|
+
const { decodeMapPack } = require("../misc/decodeMapPack.js");
|
|
5
|
+
const axios = require("axios");
|
|
6
|
+
const { headers, server } = require("../config.json");
|
|
7
|
+
const data = {
|
|
8
|
+
secret: "Wmfd2893gb7",
|
|
9
|
+
page: page - 1
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let res = await axios.post(server + "getGJMapPacks21.php", data, {
|
|
13
|
+
headers: headers
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
let firstMapPack = res.data.split("|")[0];
|
|
17
|
+
let secondMapPack = res.data.split("|")[1].split("|")[0];
|
|
18
|
+
let thirdMapPack = res.data.split("|")[2].split("|")[0];
|
|
19
|
+
let fourthMapPack = res.data.split("|")[3].split("|")[0];
|
|
20
|
+
let fifthMapPack = res.data.split("|")[4].split("|")[0];
|
|
21
|
+
let sixthMapPack;
|
|
22
|
+
let seventhMapPack;
|
|
23
|
+
let eighthMapPack;
|
|
24
|
+
let ninthMapPack;
|
|
25
|
+
let tenthMapPack;
|
|
26
|
+
let result = [decodeMapPack(firstMapPack),decodeMapPack(secondMapPack),decodeMapPack(thirdMapPack),decodeMapPack(fourthMapPack),decodeMapPack(fifthMapPack)]
|
|
27
|
+
|
|
28
|
+
if(res.data.split("|").length - 1 == 9) {
|
|
29
|
+
sixthMapPack = res.data.split("|")[5].split("|")[0];
|
|
30
|
+
seventhMapPack = res.data.split("|")[6].split("|")[0];
|
|
31
|
+
eighthMapPack = res.data.split("|")[7].split("|")[0];
|
|
32
|
+
ninthMapPack = res.data.split("|")[8].split("|")[0];
|
|
33
|
+
tenthMapPack = res.data.split("|")[9].split("|")[0];
|
|
34
|
+
result.push(decodeMapPack(sixthMapPack),decodeMapPack(seventhMapPack),decodeMapPack(eighthMapPack),decodeMapPack(ninthMapPack),decodeMapPack(tenthMapPack))
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
}
|
package/functions/getProfile.js
CHANGED
|
@@ -73,13 +73,14 @@ module.exports = {
|
|
|
73
73
|
} else {
|
|
74
74
|
stars = stars;
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
if(dataWoSkins.split("3:")[3] !== undefined) {
|
|
77
78
|
if(dataWoSkins.split("3:")[3].split(":46:")[0] == "") {
|
|
78
79
|
stars = dataWoSkins.split("3:")[4].split(":46:")[0];
|
|
79
80
|
} else {
|
|
80
81
|
stars = stars;
|
|
81
82
|
}
|
|
82
|
-
}
|
|
83
|
+
}
|
|
83
84
|
|
|
84
85
|
let ytLnk = `htps://youtube.com/channel/${youtube}`;
|
|
85
86
|
let twitterLnk = `https://twitter.com/${twitter}`;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
uploadAccountPost:
|
|
3
|
+
async function(content, str, password) {
|
|
4
|
+
const {encURLSafeBase64} = require("./encURLSafeBase64.js");
|
|
5
|
+
if(!content || content == "") throw new Error("Please provide an account post content!");
|
|
6
|
+
if(!str || str == "") throw new Error("Please provide a user ID or name!");
|
|
7
|
+
if(!password || password == "") throw new Error("Please provide a password!");
|
|
8
|
+
const axios = require("axios");
|
|
9
|
+
const { headers, server } = require("../config.json");
|
|
10
|
+
|
|
11
|
+
const data = {
|
|
12
|
+
gameVersion: 21,
|
|
13
|
+
binaryVersion: 35,
|
|
14
|
+
gdw: 0,
|
|
15
|
+
str: str,
|
|
16
|
+
secret: "Wmfd2893gb7"
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
let r = await axios.post(server + "getGJUsers20.php", data, {
|
|
20
|
+
headers: headers
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
if(r.data == -1) throw new Error("-1 This user is not found.")
|
|
24
|
+
let id = r.data.split(":16:")[1].split(":3:")[0];
|
|
25
|
+
if(Number(id) < 71 || id.includes(":")) id = r.data.split(":16:")[2].split(":3:")[0];
|
|
26
|
+
|
|
27
|
+
const XOR = require("../misc/xor.js");
|
|
28
|
+
const xor = new XOR();
|
|
29
|
+
|
|
30
|
+
const comment = encURLSafeBase64(content);
|
|
31
|
+
|
|
32
|
+
let uACdata = {
|
|
33
|
+
gameVersion: 21,
|
|
34
|
+
binaryVersion: 35,
|
|
35
|
+
gdw: 0,
|
|
36
|
+
accountID: id,
|
|
37
|
+
secret: "Wmfd2893gb7",
|
|
38
|
+
gjp: xor.encrypt(password, 37526),
|
|
39
|
+
comment: comment,
|
|
40
|
+
cType: 1
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
let res = await axios.post(server + "uploadGJAccComment20.php", uACdata, {
|
|
44
|
+
headers: headers
|
|
45
|
+
}).catch(e => {
|
|
46
|
+
if(e.response.status == 500) throw new Error("500 Error: couldn't post!");
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
if(res.data.toString().toLowerCase() == "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).")
|
|
50
|
+
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
uploadComment:
|
|
3
|
+
async function(comment, id, user, password, percent = 0) {
|
|
4
|
+
if(!comment || comment == "") throw new Error("Please provide a comment!");
|
|
5
|
+
if(!id || id == "") throw new Error("Please provide a level ID!");
|
|
6
|
+
if(!user || user == "") throw new Error("Please provide a username or a player ID!");
|
|
7
|
+
if(!password || password == "") throw new Error("Please provide a password!");
|
|
8
|
+
if(Number(percent) > 100) throw new Error("The percentage cannot be more than 100!");
|
|
9
|
+
|
|
10
|
+
const { gjp } = require("../misc/gjp.js");
|
|
11
|
+
const { encURLSafeBase64 } = require("./encURLSafeBase64.js");
|
|
12
|
+
const axios = require("axios");
|
|
13
|
+
const { headers, server } = require("../config.json");
|
|
14
|
+
const crypto = require('crypto')
|
|
15
|
+
|
|
16
|
+
function sha1(data) {
|
|
17
|
+
return crypto.createHash("sha1").update(data, "binary").digest("hex");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const data = {
|
|
21
|
+
gameVersion: 21,
|
|
22
|
+
binaryVersion: 35,
|
|
23
|
+
gdw: 0,
|
|
24
|
+
str: user,
|
|
25
|
+
secret: "Wmfd2893gb7"
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
let r = await axios.post(server + "getGJUsers20.php", data, {
|
|
29
|
+
headers: headers
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if(r.data == -1) throw new Error("-1 This user is not found.")
|
|
33
|
+
let username = r.data.split("1:")[1].split(":2:")[0];
|
|
34
|
+
let accID = r.data.split(":16:")[1].split(":3:")[0];
|
|
35
|
+
if(Number(accID) < 71 || accID.includes(":")) accID = r.data.split(":16:")[2].split(":3:")[0];
|
|
36
|
+
|
|
37
|
+
const XOR = require("../misc/xor.js");
|
|
38
|
+
const xor = new XOR();
|
|
39
|
+
|
|
40
|
+
let chkStr = username + encURLSafeBase64(comment) + Number(id) + Number(percent) + "0xPT6iUrtws0J";
|
|
41
|
+
let chk = xor.encrypt(sha1(chkStr), 29481);
|
|
42
|
+
|
|
43
|
+
const uCdata = {
|
|
44
|
+
accountID: accID,
|
|
45
|
+
gjp: gjp(password),
|
|
46
|
+
userName: username,
|
|
47
|
+
comment: encURLSafeBase64(comment),
|
|
48
|
+
levelID: id,
|
|
49
|
+
percent: percent,
|
|
50
|
+
chk: chk,
|
|
51
|
+
secret: "Wmfd2893gb7"
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let res = await axios.post(server + "uploadGJComment21.php", uCdata, {
|
|
55
|
+
headers: headers
|
|
56
|
+
}).catch(e => {
|
|
57
|
+
let edata = e.response.data;
|
|
58
|
+
if(edata == '') edata = "Whoops, the servers have rejected your request!"
|
|
59
|
+
throw new Error(edata)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/index.js
CHANGED
|
@@ -10,6 +10,10 @@ const { reportLevel } = require("./functions/reportLevel.js");
|
|
|
10
10
|
const { getComments } = require("./functions/getComments.js");
|
|
11
11
|
const { getCommentHistory } = require("./functions/getCommentHistory.js");
|
|
12
12
|
const { getGauntlets } = require("./functions/getGauntlets.js");
|
|
13
|
+
const { getAccountPosts } = require("./functions/getAccountPosts.js");
|
|
14
|
+
const { uploadAccountPost } = require("./functions/uploadAccountPost.js");
|
|
15
|
+
const { uploadComment } = require("./functions/uploadComment.js");
|
|
16
|
+
const { getMapPacks } = require("./functions/getMapPacks.js");
|
|
13
17
|
|
|
14
18
|
module.exports.dlLevel = dlLevel;
|
|
15
19
|
module.exports.getSongInfo = getSongInfo;
|
|
@@ -22,4 +26,8 @@ module.exports.getProfile = getProfile;
|
|
|
22
26
|
module.exports.reportLevel = reportLevel;
|
|
23
27
|
module.exports.getComments = getComments;
|
|
24
28
|
module.exports.getCommentHistory = getCommentHistory;
|
|
25
|
-
module.exports.getGauntlets = getGauntlets;
|
|
29
|
+
module.exports.getGauntlets = getGauntlets;
|
|
30
|
+
module.exports.getAccountPosts = getAccountPosts;
|
|
31
|
+
module.exports.uploadAccountPost = uploadAccountPost;
|
|
32
|
+
module.exports.uploadComment = uploadComment;
|
|
33
|
+
module.exports.getMapPacks = getMapPacks;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
decodeAccountPost:
|
|
3
|
+
function(post) {
|
|
4
|
+
const bs = require("js-base64");
|
|
5
|
+
|
|
6
|
+
let postContent = post.split("2~")[1].split("~4~")[0];
|
|
7
|
+
let likes = post.split("~4~")[1].split("~9~")[0];
|
|
8
|
+
let age = post.split("~9~")[1].split("~6~")[0];
|
|
9
|
+
|
|
10
|
+
const result = {
|
|
11
|
+
content: bs.decode(postContent.replace(/_/g, '/').replace(/-/g, '+')).trim(),
|
|
12
|
+
likes: Number(likes),
|
|
13
|
+
age: age
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
decodeMapPack:
|
|
3
|
+
function(mp) {
|
|
4
|
+
let name = mp.split(":2:")[1].split(":3:")[0];
|
|
5
|
+
let unarrayedList = mp.split(":3:")[1].split(":4:")[0].split(":4")[0];
|
|
6
|
+
let stars = mp.split(":4:")[1].split(":5:")[0];
|
|
7
|
+
let coins = mp.split(":5:")[1].split(":6:")[0];
|
|
8
|
+
let difficulty = mp.split(":6:")[1].split(":7:")[0];
|
|
9
|
+
|
|
10
|
+
if(unarrayedList.includes(":")) unarrayedList = mp.split(":3:")[2].split(":4:")[0]
|
|
11
|
+
|
|
12
|
+
let firstLvl = unarrayedList.split(",")[0];
|
|
13
|
+
let secondLvl = unarrayedList.split(",")[1].split(",")[0];
|
|
14
|
+
let thirdLvl = unarrayedList.split(",")[2].split(",")[0];
|
|
15
|
+
|
|
16
|
+
if(name.includes(":")) name = name.split("2:")[1]
|
|
17
|
+
|
|
18
|
+
let difficultyDecoder = {
|
|
19
|
+
"0": "Auto",
|
|
20
|
+
"1": "Easy",
|
|
21
|
+
"2": "Normal",
|
|
22
|
+
"3": "Hard",
|
|
23
|
+
"4": "Harder",
|
|
24
|
+
"5": "Insane",
|
|
25
|
+
"6": "Hard Demon",
|
|
26
|
+
"7": "Easy Demon",
|
|
27
|
+
"8": "Medium Demon",
|
|
28
|
+
"9": "Insane Demon",
|
|
29
|
+
"10": "Extreme Demon",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if(coins.startsWith("5:")) {
|
|
33
|
+
coins = coins.split("5:")[1];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if(mp.split(":5:")[2] !== undefined) {
|
|
37
|
+
if(coins.includes(":")) {
|
|
38
|
+
coins = mp.split(":5:")[2].split(":6:")[0];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if(coins.startsWith("5:")) coins = coins.split("5:")[1];
|
|
43
|
+
if(coins.startsWith("7:")) coins = mp.split(":5:")[1].split(":6:")[0];
|
|
44
|
+
if(coins.endsWith(":6")) coins = coins.split(":6")[0];
|
|
45
|
+
|
|
46
|
+
const result = {
|
|
47
|
+
name: name,
|
|
48
|
+
levels: [Number(firstLvl),Number(secondLvl),Number(thirdLvl)],
|
|
49
|
+
stars: Number(stars),
|
|
50
|
+
coins: Number(coins)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
}
|
package/misc/gjp.js
ADDED