-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcollector.js
204 lines (175 loc) · 7.18 KB
/
collector.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
import { fetch } from "bun";
import { initializeDatabase } from './schema.js';
import { unlink } from 'node:fs/promises';
import { existsSync } from 'node:fs';
const groupId = process.env.groupid;
const memberFile = Bun.file(".users.json");
const memberMap = await memberFile.json();
const DB_PATH = 'trackmania_wrapped.db';
async function getAuthToken() {
console.log("🔑 Getting auth token...");
const response1 = await fetch('https://public-ubiservices.ubi.com/v3/profiles/sessions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Ubi-AppId': '86263886-327a-4328-ac69-527f0d20a237',
'Authorization': `Basic ${process.env.userpw}`,
'User-Agent': 'Local Leaderboard'
},
body: JSON.stringify({ "audience": "NadeoLiveServices" })
});
const data1 = await response1.json();
if (data1.httpCode === 429) {
return new Response("Rate limiting hat gekickt", { status: 429 });
}
const response2 = await fetch('https://prod.trackmania.core.nadeo.online/v2/authentication/token/ubiservices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `ubi_v1 t=${data1.ticket}`,
'User-Agent': 'Local Leaderboard'
},
body: JSON.stringify({ "audience": "NadeoLiveServices" })
});
const data2 = await response2.json();
console.log("✅ Auth token received");
return { accessToken: data2.accessToken };
}
export async function collectYearData() {
const currentYear = new Date().getFullYear();
console.log(`🎮 Starting Trackmania data collection for ${currentYear}`);
// Delete old database if it exists
if (existsSync(DB_PATH)) {
console.log("🗑️ Removing old database...");
await unlink(DB_PATH);
}
const db = await initializeDatabase();
const token = await getAuthToken();
if (!token.accessToken) {
throw new Error("Failed to get auth token");
}
// Update the months loop to only get months up to current month
const currentMonth = new Date().getMonth(); // 0-based index
console.log("📅 Fetching monthly campaigns...");
const monthPromises = [];
for (let offset = 0; offset <= currentMonth; offset++) {
monthPromises.push(
fetch('https://live-services.trackmania.nadeo.live/api/token/campaign/month?length=1&offset=' + offset, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `nadeo_v1 t=${token.accessToken}`,
'User-Agent': 'Trackmania Wrapped'
}
}).then(r => r.json())
);
}
const months = await Promise.all(monthPromises);
console.log("✅ Monthly campaigns fetched");
// Collect all map UIDs
console.log("🗺️ Processing map information...");
const mapUids = new Map();
months.forEach((monthData) => {
const month = monthData.monthList[0].month; // Get actual month from API response
monthData.monthList[0].days.forEach(day => {
if (day.mapUid) {
mapUids.set(day.mapUid, {
month: month,
monthDay: day.monthDay
});
}
});
});
console.log(`📍 Found ${mapUids.size} unique maps`);
// Get map details in batches of 50
const mapUidArray = [...mapUids.keys()];
const mapBatches = [];
for (let i = 0; i < mapUidArray.length; i += 50) {
const batch = mapUidArray.slice(i, i + 50);
mapBatches.push(batch);
}
console.log("🎯 Fetching map details...");
let processedMaps = 0;
let lastProgressStep = 0;
for (const batch of mapBatches) {
const mapCommaList = batch.join(',');
const mapData = await fetch(
`https://live-services.trackmania.nadeo.live/api/token/map/get-multiple?mapUidList=${mapCommaList}`,
{
headers: {
'Authorization': `nadeo_v1 t=${token.accessToken}`,
'User-Agent': 'Trackmania Wrapped'
}
}
).then(r => r.json());
// Update map storage to use currentYear
const stmt = db.prepare(`
INSERT OR REPLACE INTO maps (uid, day, month, year, bronze_time, silver_time, gold_time, author_time, thumbnail_url)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
mapData.mapList.forEach(map => {
const dateInfo = mapUids.get(map.uid);
stmt.run(
map.uid,
dateInfo.monthDay,
dateInfo.month,
currentYear,
map.bronzeTime,
map.silverTime,
map.goldTime,
map.authorTime,
map.thumbnailUrl
);
});
processedMaps += batch.length;
const currentProgress = Math.floor(processedMaps/mapUids.size*100);
if (currentProgress >= lastProgressStep + 10) {
console.log(` Progress: ${currentProgress}%`);
lastProgressStep = Math.floor(currentProgress/10) * 10;
}
}
console.log("✅ Map details stored in database");
// Get leaderboard data for each map
console.log("🏆 Fetching leaderboard data...");
let processedLeaderboards = 0;
lastProgressStep = 0;
for (const mapUid of mapUids.keys()) {
const leaderboard = await fetch(
`https://live-services.trackmania.nadeo.live/api/token/leaderboard/group/Personal_Best/map/${mapUid}/club/${groupId}/top?length=10&offset=0`,
{
headers: {
'Authorization': `nadeo_v1 t=${token.accessToken}`,
'User-Agent': 'Trackmania Wrapped'
}
}
).then(r => r.json());
const stmt = db.prepare(`
INSERT OR REPLACE INTO runs (map_uid, user_id, time, medal, position)
VALUES (?, ?, ?, ?, ?)
`);
const mapTimes = db.prepare('SELECT * FROM maps WHERE uid = ?').get(mapUid);
leaderboard.top?.forEach(entry => {
let medal = '💩';
if (entry.score <= mapTimes.author_time) medal = '🏎️';
else if (entry.score <= mapTimes.gold_time) medal = '🥇';
else if (entry.score <= mapTimes.silver_time) medal = '🥈';
else if (entry.score <= mapTimes.bronze_time) medal = '🥉';
stmt.run(
mapUid,
entry.accountId,
entry.score,
medal,
entry.position
);
});
processedLeaderboards++;
const currentProgress = Math.floor(processedLeaderboards/mapUids.size*100);
if (currentProgress >= lastProgressStep + 10) {
console.log(` Progress: ${currentProgress}%`);
lastProgressStep = Math.floor(currentProgress/10) * 10;
}
}
console.log("✅ Leaderboard data stored in database");
console.log("🎉 Data collection complete!");
db.close();
}