r6-data.js 1.2.1 → 1.3.1
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 +78 -12
- package/index.js +2 -0
- package/methods/createDiscordR6Webhook.js +217 -0
- package/package.json +10 -5
package/README.md
CHANGED
|
@@ -111,21 +111,87 @@ The `getPlayerStats()` function accepts an object with the following parameters:
|
|
|
111
111
|
- `board_id`: (Optional) The game mode to filter statistics - "casual", "event", "warmup", "standard", or "ranked"
|
|
112
112
|
|
|
113
113
|
### Player Statistics Response
|
|
114
|
-
|
|
114
|
+
When using `getPlayerStats()`, you'll receive detailed gameplay statistics, including:
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
- Rank information
|
|
117
|
+
- MMR (Matchmaking Rating)
|
|
118
|
+
- Win/loss records
|
|
119
|
+
- Seasonal performance data
|
|
120
|
+
- Skill metrics across different gameplay modes
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
You can filter these statistics by game mode using the `board_id` parameter:
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
- `casual`: Statistics for casual matches
|
|
125
|
+
- `event`: Statistics for limited-time events
|
|
126
|
+
- `warmup`: Statistics for warmup matches
|
|
127
|
+
- `standard`: Statistics for standard matches
|
|
128
|
+
- `ranked`: Statistics for ranked competitive matches
|
|
129
|
+
|
|
130
|
+
## Creating Discord Webhooks for R6 Stats
|
|
131
|
+
|
|
132
|
+
The `createDiscordR6Webhook()` function allows you to send Rainbow Six Siege player statistics directly to a Discord channel using webhooks. This creates formatted embeds with player stats that can be customized with various options.
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const r6Info = require('r6-data.js');
|
|
136
|
+
|
|
137
|
+
async function main() {
|
|
138
|
+
try {
|
|
139
|
+
// First, get player statistics
|
|
140
|
+
const playerStats = await r6Info.getPlayerStats({
|
|
141
|
+
nameOnPlatform: 'PlayerName',
|
|
142
|
+
platformType: 'uplay',
|
|
143
|
+
platform_families: 'pc'
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Send stats to Discord webhook
|
|
147
|
+
const webhookResult = await r6Info.createDiscordR6Webhook(
|
|
148
|
+
'https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN',
|
|
149
|
+
playerStats,
|
|
150
|
+
{
|
|
151
|
+
playerName: 'PlayerName',
|
|
152
|
+
title: 'Rainbow Six Siege Stats',
|
|
153
|
+
message: 'Here are the latest R6 stats!',
|
|
154
|
+
color: 0xF99E1A, // Orange color
|
|
155
|
+
avatarUrl: 'https://example.com/avatar.png'
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
console.log('Webhook sent successfully:', webhookResult);
|
|
160
|
+
|
|
161
|
+
} catch (error) {
|
|
162
|
+
console.error('Error sending webhook:', error.message);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
main();
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Parameters
|
|
170
|
+
The `createDiscordR6Webhook()` function accepts the following parameters:
|
|
171
|
+
- `webhookUrl`: (Required) The Discord webhook URL
|
|
172
|
+
- `playerData`: (Required) Player statistics data from getPlayerStats() or getAccountInfo()
|
|
173
|
+
- `options`: (Required) Configuration object with the following properties:
|
|
174
|
+
- `playerName`: (Required) The player's name to display
|
|
175
|
+
- `title`: (Optional) Custom title for the embed (default: "Rainbow Six Siege Stats")
|
|
176
|
+
- `message`: (Optional) Custom message content above the embed
|
|
177
|
+
- `color`: (Optional) Embed color in hexadecimal format (default: 0xF99E1A)
|
|
178
|
+
- `avatarUrl`: (Optional) URL for the player's avatar thumbnail
|
|
179
|
+
|
|
180
|
+
### Supported Data Formats
|
|
181
|
+
The function automatically detects and formats different data sources:
|
|
182
|
+
|
|
183
|
+
`Ubisoft API data`: From getPlayerStats() - displays ranked/standard statistics
|
|
184
|
+
`Steam data`: Custom Steam-formatted statistics
|
|
185
|
+
`Custom data`: Any custom statistics object
|
|
186
|
+
|
|
187
|
+
### Discord Webhook Setup
|
|
188
|
+
To use this function, you need to create a webhook in your Discord server:
|
|
189
|
+
|
|
190
|
+
1. Go to your Discord server settings
|
|
191
|
+
2. Navigate to Integrations → Webhooks
|
|
192
|
+
3. Click "New Webhook"
|
|
193
|
+
4. Copy the webhook URL
|
|
194
|
+
5. Use this URL in the `createDiscordR6Webhook()` function
|
|
129
195
|
|
|
130
196
|
## Searching Across All Entities
|
|
131
197
|
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ const getUniversalSkins = require('./methods/getUniversalSkins');
|
|
|
10
10
|
const getSearchAll = require('./methods/getSearchAll');
|
|
11
11
|
const getAccountInfo = require('./methods/getAccountInfo');
|
|
12
12
|
const getPlayerStats = require('./methods/getPlayerStats');
|
|
13
|
+
const createDiscordR6Webhook = require('./methods/createDiscordR6Webhook');
|
|
13
14
|
|
|
14
15
|
const r6Data = {
|
|
15
16
|
getMaps,
|
|
@@ -24,6 +25,7 @@ const r6Data = {
|
|
|
24
25
|
getSearchAll,
|
|
25
26
|
getAccountInfo,
|
|
26
27
|
getPlayerStats,
|
|
28
|
+
createDiscordR6Webhook,
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
module.exports = r6Data;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
const axiosInstance = require('../axiosInstance/axiosInstance');
|
|
2
|
+
|
|
3
|
+
async function createDiscordR6Webhook(webhookUrl, playerData, options = {}) {
|
|
4
|
+
try {
|
|
5
|
+
if (!webhookUrl || !playerData) {
|
|
6
|
+
throw new Error('Missing required parameters: webhookUrl and playerData are required');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (!options.playerName) {
|
|
10
|
+
throw new Error('Missing required parameter: options.playerName is required');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Validate webhook URL format
|
|
14
|
+
if (!webhookUrl.includes('discord.com/api/webhooks/')) {
|
|
15
|
+
throw new Error('Invalid Discord webhook URL format');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const embed = createR6StatsEmbed(playerData, options);
|
|
19
|
+
|
|
20
|
+
const payload = {
|
|
21
|
+
embeds: [embed]
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Add custom message if provided
|
|
25
|
+
if (options.message) {
|
|
26
|
+
payload.content = options.message;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const response = await axiosInstance.post(webhookUrl, payload);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
messageId: response.headers['x-discord-message-id'],
|
|
34
|
+
sentAt: new Date().toISOString()
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Error during createDiscordR6Webhook request:', error.message);
|
|
39
|
+
if (error.response && error.response.status === 404) {
|
|
40
|
+
throw new Error('Discord webhook not found - check webhook URL');
|
|
41
|
+
}
|
|
42
|
+
if (error.response && error.response.status === 401) {
|
|
43
|
+
throw new Error('Discord webhook unauthorized - webhook may be disabled');
|
|
44
|
+
}
|
|
45
|
+
if (error.response && error.response.status === 429) {
|
|
46
|
+
throw new Error('Discord rate limit exceeded - try again later');
|
|
47
|
+
}
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function createR6StatsEmbed(playerData, options) {
|
|
53
|
+
let stats, dataSource;
|
|
54
|
+
|
|
55
|
+
if (playerData.stats) {
|
|
56
|
+
// Steam data format
|
|
57
|
+
stats = playerData.stats;
|
|
58
|
+
dataSource = 'Steam';
|
|
59
|
+
} else if (playerData.platform_families_full_profiles) {
|
|
60
|
+
// Ubisoft API data format - from getStats method
|
|
61
|
+
stats = parseUbisoftStatsFromResponse(playerData);
|
|
62
|
+
dataSource = 'Ubisoft';
|
|
63
|
+
} else if (Array.isArray(playerData)) {
|
|
64
|
+
// Ubisoft API data format - direct array
|
|
65
|
+
stats = parseUbisoftStats(playerData);
|
|
66
|
+
dataSource = 'Ubisoft';
|
|
67
|
+
} else {
|
|
68
|
+
// Fallback
|
|
69
|
+
stats = playerData;
|
|
70
|
+
dataSource = 'Custom';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const embed = {
|
|
74
|
+
title: `${options.title || 'Rainbow Six Siege Stats'}`,
|
|
75
|
+
description: `Stats for **${options.playerName}**`,
|
|
76
|
+
color: options.color || 0xF99E1A,
|
|
77
|
+
fields: createStatsFields(stats, dataSource),
|
|
78
|
+
thumbnail: {
|
|
79
|
+
url: options.avatarUrl || 'https://ubisoft-avatars.akamaized.net/default_256_256.png'
|
|
80
|
+
},
|
|
81
|
+
footer: {
|
|
82
|
+
text: `Data from ${dataSource} | r6-data.js`
|
|
83
|
+
},
|
|
84
|
+
timestamp: new Date().toISOString()
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
return embed;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parseUbisoftStatsFromResponse(response) {
|
|
91
|
+
const platformProfile = response.platform_families_full_profiles[0];
|
|
92
|
+
if (!platformProfile || !platformProfile.board_ids_full_profiles) {
|
|
93
|
+
return { ranked: null, standard: null };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const boardsArray = platformProfile.board_ids_full_profiles;
|
|
97
|
+
return parseUbisoftStats(boardsArray);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function parseUbisoftStats(data) {
|
|
101
|
+
let rankedStats = null;
|
|
102
|
+
let standardStats = null;
|
|
103
|
+
|
|
104
|
+
for (const board of data) {
|
|
105
|
+
if (board.board_id === 'ranked' && board.full_profiles && board.full_profiles[0]) {
|
|
106
|
+
rankedStats = {
|
|
107
|
+
profile: board.full_profiles[0].profile,
|
|
108
|
+
season_statistics: board.full_profiles[0].season_statistics
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (board.board_id === 'standard' && board.full_profiles && board.full_profiles[0]) {
|
|
113
|
+
standardStats = {
|
|
114
|
+
profile: board.full_profiles[0].profile,
|
|
115
|
+
season_statistics: board.full_profiles[0].season_statistics
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
ranked: rankedStats,
|
|
122
|
+
standard: standardStats
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function createStatsFields(stats, dataSource) {
|
|
127
|
+
const fields = [];
|
|
128
|
+
|
|
129
|
+
if (dataSource === 'Steam') {
|
|
130
|
+
fields.push(
|
|
131
|
+
{
|
|
132
|
+
name: 'General Stats',
|
|
133
|
+
value: `**Matches Played:** ${stats.generalStats?.matchesPlayed || 'N/A'}\n**Win Rate:** ${stats.generalStats?.winRate || 0}%\n**Playtime:** ${stats.generalStats?.totalTimePlayedHours || 0}h`,
|
|
134
|
+
inline: true
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Combat Stats',
|
|
138
|
+
value: `**K/D Ratio:** ${stats.combatStats?.kdRatio || 'N/A'}\n**Total Kills:** ${stats.combatStats?.totalKills || 'N/A'}\n**Headshot %:** ${stats.combatStats?.headshotPercentage || 0}%`,
|
|
139
|
+
inline: true
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'Ranked Stats',
|
|
143
|
+
value: `**Ranked Matches:** ${stats.rankedStats?.rankedMatches || 'N/A'}\n**Ranked K/D:** ${stats.rankedStats?.rankedKD || 'N/A'}\n**Ranked Win Rate:** ${stats.rankedStats?.rankedWinRate || 0}%`,
|
|
144
|
+
inline: true
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
} else if (dataSource === 'Ubisoft') {
|
|
148
|
+
const rankedData = stats.ranked;
|
|
149
|
+
|
|
150
|
+
if (rankedData && rankedData.profile && rankedData.season_statistics) {
|
|
151
|
+
const profile = rankedData.profile;
|
|
152
|
+
const seasonStats = rankedData.season_statistics;
|
|
153
|
+
|
|
154
|
+
const totalMatches = (seasonStats.match_outcomes.wins || 0) + (seasonStats.match_outcomes.losses || 0);
|
|
155
|
+
const winRate = totalMatches > 0 ? Math.round((seasonStats.match_outcomes.wins / totalMatches) * 100) : 0;
|
|
156
|
+
const kd = seasonStats.deaths > 0 ? Math.round((seasonStats.kills / seasonStats.deaths) * 100) / 100 : seasonStats.kills;
|
|
157
|
+
|
|
158
|
+
fields.push(
|
|
159
|
+
{
|
|
160
|
+
name: 'Ranked Profile',
|
|
161
|
+
value: `**Rank:** ${getRankName(profile.rank)}\n**Points:** ${profile.rank_points}\n**Max Rank:** ${getRankName(profile.max_rank)}`,
|
|
162
|
+
inline: true
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: 'Performance',
|
|
166
|
+
value: `**K/D:** ${kd}\n**Win Rate:** ${winRate}%\n**Matches:** ${totalMatches}`,
|
|
167
|
+
inline: true
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'Combat Stats',
|
|
171
|
+
value: `**Kills:** ${seasonStats.kills}\n**Deaths:** ${seasonStats.deaths}\n**Wins:** ${seasonStats.match_outcomes.wins}\n**Losses:** ${seasonStats.match_outcomes.losses}`,
|
|
172
|
+
inline: true
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
} else {
|
|
176
|
+
// Fallback to standard stats if ranked not available
|
|
177
|
+
const standardData = stats.standard;
|
|
178
|
+
if (standardData && standardData.season_statistics) {
|
|
179
|
+
const seasonStats = standardData.season_statistics;
|
|
180
|
+
const totalMatches = (seasonStats.match_outcomes.wins || 0) + (seasonStats.match_outcomes.losses || 0);
|
|
181
|
+
const winRate = totalMatches > 0 ? Math.round((seasonStats.match_outcomes.wins / totalMatches) * 100) : 0;
|
|
182
|
+
const kd = seasonStats.deaths > 0 ? Math.round((seasonStats.kills / seasonStats.deaths) * 100) / 100 : seasonStats.kills;
|
|
183
|
+
|
|
184
|
+
fields.push({
|
|
185
|
+
name: 'Standard Stats',
|
|
186
|
+
value: `**K/D:** ${kd}\n**Win Rate:** ${winRate}%\n**Matches:** ${totalMatches}\n**Kills:** ${seasonStats.kills}\n**Deaths:** ${seasonStats.deaths}`,
|
|
187
|
+
inline: false
|
|
188
|
+
});
|
|
189
|
+
} else {
|
|
190
|
+
fields.push({
|
|
191
|
+
name: 'No Data',
|
|
192
|
+
value: 'No ranked or standard stats available.',
|
|
193
|
+
inline: false
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return fields;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function getRankName(rankNumber) {
|
|
203
|
+
const ranks = {
|
|
204
|
+
0: 'Unranked',
|
|
205
|
+
1: 'Copper V', 2: 'Copper IV', 3: 'Copper III', 4: 'Copper II', 5: 'Copper I',
|
|
206
|
+
6: 'Bronze V', 7: 'Bronze IV', 8: 'Bronze III', 9: 'Bronze II', 10: 'Bronze I',
|
|
207
|
+
11: 'Silver V', 12: 'Silver IV', 13: 'Silver III', 14: 'Silver II', 15: 'Silver I',
|
|
208
|
+
16: 'Gold V', 17: 'Gold IV', 18: 'Gold III', 19: 'Gold II', 20: 'Gold I',
|
|
209
|
+
21: 'Platinum V', 22: 'Platinum IV', 23: 'Platinum III', 24: 'Platinum II', 25: 'Platinum I',
|
|
210
|
+
26: 'Diamond V', 27: 'Diamond IV', 28: 'Diamond III', 29: 'Diamond II', 30: 'Diamond I',
|
|
211
|
+
31: 'Champion'
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
return ranks[rankNumber] || 'Unknown Rank';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
module.exports = createDiscordR6Webhook;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "r6-data.js",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Rainbow Six Siege API wrapper
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "Rainbow Six Siege API wrapper for player's stats, maps, operators, ranks, seasons, charms etc. Last updated Y10S3",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
@@ -39,15 +39,20 @@
|
|
|
39
39
|
"r6stats-api",
|
|
40
40
|
"siegeapi",
|
|
41
41
|
"siege-api",
|
|
42
|
-
"siege x api"
|
|
42
|
+
"siege x api",
|
|
43
|
+
"r6siege",
|
|
44
|
+
"rainbow",
|
|
45
|
+
"r6 info",
|
|
46
|
+
"r6-info",
|
|
47
|
+
"R6 info"
|
|
43
48
|
],
|
|
44
49
|
"author": "mazeor",
|
|
45
50
|
"license": "ISC",
|
|
46
51
|
"dependencies": {
|
|
47
|
-
"axios": "^1.
|
|
52
|
+
"axios": "^1.12.2",
|
|
48
53
|
"ms": "^2.1.3"
|
|
49
54
|
},
|
|
50
55
|
"devDependencies": {
|
|
51
|
-
"@types/node": "^
|
|
56
|
+
"@types/node": "^24.4.0"
|
|
52
57
|
}
|
|
53
58
|
}
|