@nekosuneprojects/nekosunevrtools 1.1.0 → 1.1.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 +111 -0
- package/package.json +14 -3
- package/src/cli.js +728 -14
- package/src/downloader/client.js +126 -0
- package/src/downloader/provider/compatible.js +127 -0
- package/src/downloader/providers.js +15 -0
- package/src/games/client.js +162 -0
- package/src/games/provider/nekosune-api.js +329 -0
- package/src/games/providers.js +14 -0
- package/src/index.d.ts +140 -0
- package/src/index.js +26 -2
- package/src/livestream/client.js +70 -0
- package/src/livestream/provider/nekosune-api.js +56 -0
- package/src/livestream/providers.js +14 -0
package/src/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const axios = require("axios");
|
|
3
|
-
const { UploadClient, EarningsClient, shortenerPresets } = require("./index");
|
|
3
|
+
const { UploadClient, EarningsClient, shortenerPresets, DownloaderClient, downloaderPresets, LivestreamClient, livestreamPresets, GamesClient, gamesPresets } = require("./index");
|
|
4
4
|
|
|
5
5
|
async function runCli(argv = process.argv.slice(2)) {
|
|
6
6
|
const parsed = parseArgs(argv);
|
|
@@ -22,15 +22,587 @@ async function runCli(argv = process.argv.slice(2)) {
|
|
|
22
22
|
if (parsed.command === "video-upload") {
|
|
23
23
|
return runVideoUploadCommand(parsed);
|
|
24
24
|
}
|
|
25
|
+
if (parsed.command === "download-mp3") {
|
|
26
|
+
return runDownloadJobCreateCommand(parsed, "mp3");
|
|
27
|
+
}
|
|
28
|
+
if (parsed.command === "download-mp4") {
|
|
29
|
+
return runDownloadJobCreateCommand(parsed, "mp4");
|
|
30
|
+
}
|
|
31
|
+
if (parsed.command === "download-job") {
|
|
32
|
+
return runDownloadJobStatusCommand(parsed);
|
|
33
|
+
}
|
|
34
|
+
if (parsed.command === "download-info") {
|
|
35
|
+
return runDownloadInfoCommand(parsed);
|
|
36
|
+
}
|
|
37
|
+
if (parsed.command === "download-search") {
|
|
38
|
+
return runDownloadSearchCommand(parsed);
|
|
39
|
+
}
|
|
40
|
+
if (parsed.command === "download-stream-url") {
|
|
41
|
+
return runDownloadStreamUrlCommand(parsed);
|
|
42
|
+
}
|
|
25
43
|
if (parsed.command === "list-shorteners") {
|
|
26
44
|
process.stdout.write(`${Object.keys(shortenerPresets).join("\n")}\n`);
|
|
27
45
|
return 0;
|
|
28
46
|
}
|
|
47
|
+
if (parsed.command === "live-kick") {
|
|
48
|
+
return runLivestreamCommand(parsed, "kick");
|
|
49
|
+
}
|
|
50
|
+
if (parsed.command === "live-twitch") {
|
|
51
|
+
return runLivestreamCommand(parsed, "twitch");
|
|
52
|
+
}
|
|
53
|
+
if (parsed.command === "live-dlive") {
|
|
54
|
+
return runLivestreamCommand(parsed, "dlive");
|
|
55
|
+
}
|
|
56
|
+
if (parsed.command === "live-trovo") {
|
|
57
|
+
return runLivestreamCommand(parsed, "trovo");
|
|
58
|
+
}
|
|
59
|
+
if (parsed.command === "live") {
|
|
60
|
+
return runLivestreamCommand(parsed, parsed.streamPlatform);
|
|
61
|
+
}
|
|
62
|
+
if (parsed.command === "coc-clan") {
|
|
63
|
+
return runClashOfClansClanCommand(parsed);
|
|
64
|
+
}
|
|
65
|
+
if (parsed.command === "coc-player") {
|
|
66
|
+
return runClashOfClansPlayerCommand(parsed);
|
|
67
|
+
}
|
|
68
|
+
if (parsed.command === "division2-player" || parsed.command === "td2-player") {
|
|
69
|
+
return runDivision2PlayerCommand(parsed);
|
|
70
|
+
}
|
|
71
|
+
if (parsed.command === "fortnite-player" || parsed.command === "fn-player") {
|
|
72
|
+
return runFortnitePlayerCommand(parsed);
|
|
73
|
+
}
|
|
74
|
+
if (parsed.command === "fortnite-creatorcode" || parsed.command === "fn-creatorcode") {
|
|
75
|
+
return runFortniteCreatorCodeCommand(parsed);
|
|
76
|
+
}
|
|
77
|
+
if (parsed.command === "fortnite-item-shop" || parsed.command === "fn-item-shop") {
|
|
78
|
+
return runFortniteItemShopCommand(parsed);
|
|
79
|
+
}
|
|
80
|
+
if (parsed.command === "wynncraft-profile" || parsed.command === "wc-profile") {
|
|
81
|
+
return runWynncraftProfileCommand(parsed);
|
|
82
|
+
}
|
|
83
|
+
if (parsed.command === "hypixel-profile" || parsed.command === "hp-profile") {
|
|
84
|
+
return runHypixelProfileCommand(parsed);
|
|
85
|
+
}
|
|
86
|
+
if (parsed.command === "rocketleague-player" || parsed.command === "rl-player") {
|
|
87
|
+
return runRocketLeaguePlayerCommand(parsed);
|
|
88
|
+
}
|
|
89
|
+
if (parsed.command === "apexlegends-player" || parsed.command === "apex-player") {
|
|
90
|
+
return runApexLegendsPlayerCommand(parsed);
|
|
91
|
+
}
|
|
92
|
+
if (parsed.command === "battlefield1-player" || parsed.command === "bf1-player") {
|
|
93
|
+
return runBattlefield1PlayerCommand(parsed);
|
|
94
|
+
}
|
|
95
|
+
if (parsed.command === "battlefield5-player" || parsed.command === "bf5-player") {
|
|
96
|
+
return runBattlefield5PlayerCommand(parsed);
|
|
97
|
+
}
|
|
98
|
+
if (parsed.command === "battlefield2042-player" || parsed.command === "bf2042-player") {
|
|
99
|
+
return runBattlefield2042PlayerCommand(parsed);
|
|
100
|
+
}
|
|
101
|
+
if (parsed.command === "battlefield6-player" || parsed.command === "bf6-player") {
|
|
102
|
+
return runBattlefield6PlayerCommand(parsed);
|
|
103
|
+
}
|
|
104
|
+
if (parsed.command === "list-livestream-presets") {
|
|
105
|
+
process.stdout.write(`${Object.keys(livestreamPresets).join("\n")}\n`);
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
if (parsed.command === "list-games-presets") {
|
|
109
|
+
process.stdout.write(`${Object.keys(gamesPresets).join("\n")}\n`);
|
|
110
|
+
return 0;
|
|
111
|
+
} if (parsed.command === "list-download-presets") {
|
|
112
|
+
process.stdout.write(`${Object.keys(downloaderPresets).join("\n")}\n`);
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
29
115
|
|
|
30
116
|
printHelp();
|
|
31
117
|
return 1;
|
|
32
118
|
}
|
|
33
119
|
|
|
120
|
+
function buildDownloaderClient(parsed) {
|
|
121
|
+
return new DownloaderClient({
|
|
122
|
+
apiKey: parsed.apiKey || null,
|
|
123
|
+
baseUrl: parsed.downloaderBaseUrl || parsed.baseUrl || null,
|
|
124
|
+
preset: parsed.downloaderPreset || "nekosune",
|
|
125
|
+
timeoutMs: parsed.timeoutMs || 120000
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildLivestreamClient(parsed) {
|
|
130
|
+
return new LivestreamClient({
|
|
131
|
+
apiKey: parsed.apiKey || null,
|
|
132
|
+
baseUrl: parsed.livestreamBaseUrl || null,
|
|
133
|
+
preset: parsed.livestreamPreset || "nekosune",
|
|
134
|
+
timeoutMs: parsed.timeoutMs || 60000
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function buildGamesClient(parsed) {
|
|
139
|
+
return new GamesClient({
|
|
140
|
+
apiKey: parsed.apiKey || null,
|
|
141
|
+
baseUrl: parsed.gamesBaseUrl || null,
|
|
142
|
+
preset: parsed.gamesPreset || "nekosune",
|
|
143
|
+
timeoutMs: parsed.timeoutMs || 60000
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function runLivestreamCommand(parsed, explicitPlatform) {
|
|
148
|
+
const platform = explicitPlatform || parsed.streamPlatform;
|
|
149
|
+
const username = parsed.username || parsed.url;
|
|
150
|
+
if (!platform) {
|
|
151
|
+
throw new Error("Missing livestream platform. Use live-kick/live-twitch/live-dlive/live-trovo or --stream-platform.");
|
|
152
|
+
}
|
|
153
|
+
if (!username) {
|
|
154
|
+
throw new Error("Missing --username for livestream command.");
|
|
155
|
+
}
|
|
156
|
+
if (!parsed.apiKey) {
|
|
157
|
+
throw new Error("Missing --apikey for livestream command.");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const client = buildLivestreamClient(parsed);
|
|
161
|
+
let result;
|
|
162
|
+
if (platform === "kick") {
|
|
163
|
+
result = await client.getKick(username);
|
|
164
|
+
} else if (platform === "twitch") {
|
|
165
|
+
result = await client.getTwitch(username);
|
|
166
|
+
} else if (platform === "dlive") {
|
|
167
|
+
result = await client.getDlive(username);
|
|
168
|
+
} else if (platform === "trovo") {
|
|
169
|
+
result = await client.getTrovo(username);
|
|
170
|
+
} else {
|
|
171
|
+
result = await client.getByPlatform(platform, username);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (parsed.json) {
|
|
175
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
176
|
+
} else {
|
|
177
|
+
const online = result && result.livestream ? result.livestream.online : null;
|
|
178
|
+
process.stdout.write(`${result.displayname || result.username || username} online=${String(Boolean(online))}\n`);
|
|
179
|
+
}
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function runClashOfClansClanCommand(parsed) {
|
|
184
|
+
const tag = parsed.clanTag || parsed.tag;
|
|
185
|
+
if (!tag) {
|
|
186
|
+
throw new Error("Missing --clan-tag for coc-clan.");
|
|
187
|
+
}
|
|
188
|
+
if (!parsed.apiKey) {
|
|
189
|
+
throw new Error("Missing --apikey for coc-clan.");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const client = buildGamesClient(parsed);
|
|
193
|
+
const result = await client.getClashOfClansClan(tag);
|
|
194
|
+
if (parsed.json) {
|
|
195
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
196
|
+
} else {
|
|
197
|
+
process.stdout.write(`${result.name || "Clan"} ${result.tag || ""} members=${result.memberCount || 0}\n`);
|
|
198
|
+
}
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function runClashOfClansPlayerCommand(parsed) {
|
|
203
|
+
const tag = parsed.playerTag || parsed.tag;
|
|
204
|
+
if (!tag) {
|
|
205
|
+
throw new Error("Missing --player-tag for coc-player.");
|
|
206
|
+
}
|
|
207
|
+
if (!parsed.apiKey) {
|
|
208
|
+
throw new Error("Missing --apikey for coc-player.");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const client = buildGamesClient(parsed);
|
|
212
|
+
const result = await client.getClashOfClansPlayer(tag);
|
|
213
|
+
if (parsed.json) {
|
|
214
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
215
|
+
} else {
|
|
216
|
+
process.stdout.write(`${result.name || "Player"} ${result.tag || ""} th=${result.townHallLevel || "?"}\n`);
|
|
217
|
+
}
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async function runDivision2PlayerCommand(parsed) {
|
|
222
|
+
const username = parsed.username || parsed.url;
|
|
223
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
224
|
+
|
|
225
|
+
if (!username) {
|
|
226
|
+
throw new Error("Missing --username for division2-player.");
|
|
227
|
+
}
|
|
228
|
+
if (!parsed.apiKey) {
|
|
229
|
+
throw new Error("Missing --apikey for division2-player.");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const client = buildGamesClient(parsed);
|
|
233
|
+
const result = await client.getDivision2Player(username, platform);
|
|
234
|
+
if (parsed.json) {
|
|
235
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
236
|
+
} else {
|
|
237
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
238
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
239
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
240
|
+
}
|
|
241
|
+
return 0;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function runFortnitePlayerCommand(parsed) {
|
|
245
|
+
const username = parsed.username || parsed.url;
|
|
246
|
+
const timeWindow = parsed.timeWindow || "lifetime";
|
|
247
|
+
|
|
248
|
+
if (!username) {
|
|
249
|
+
throw new Error("Missing --username for fortnite-player.");
|
|
250
|
+
}
|
|
251
|
+
if (!parsed.apiKey) {
|
|
252
|
+
throw new Error("Missing --apikey for fortnite-player.");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const client = buildGamesClient(parsed);
|
|
256
|
+
const result = await client.getFortnitePlayer(username, timeWindow);
|
|
257
|
+
if (parsed.json) {
|
|
258
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
259
|
+
} else {
|
|
260
|
+
const accountName = result && result.data && result.data.account ? result.data.account.name : username;
|
|
261
|
+
const wins = result && result.data && result.data.stats && result.data.stats.all && result.data.stats.all.overall
|
|
262
|
+
? result.data.stats.all.overall.wins
|
|
263
|
+
: 0;
|
|
264
|
+
process.stdout.write(`${accountName} timeWindow=${timeWindow} wins=${wins}\n`);
|
|
265
|
+
}
|
|
266
|
+
return 0;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function runFortniteCreatorCodeCommand(parsed) {
|
|
270
|
+
const creatorCode = parsed.creatorCode || parsed.code || parsed.username || parsed.url;
|
|
271
|
+
|
|
272
|
+
if (!creatorCode) {
|
|
273
|
+
throw new Error("Missing --creator-code for fortnite-creatorcode.");
|
|
274
|
+
}
|
|
275
|
+
if (!parsed.apiKey) {
|
|
276
|
+
throw new Error("Missing --apikey for fortnite-creatorcode.");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const client = buildGamesClient(parsed);
|
|
280
|
+
const result = await client.getFortniteCreatorCode(creatorCode);
|
|
281
|
+
if (parsed.json) {
|
|
282
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
283
|
+
} else {
|
|
284
|
+
const code = result && result.data ? result.data.code : creatorCode;
|
|
285
|
+
const status = result && result.data ? result.data.status : "unknown";
|
|
286
|
+
process.stdout.write(`${code} status=${status}\n`);
|
|
287
|
+
}
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function runFortniteItemShopCommand(parsed) {
|
|
292
|
+
if (!parsed.apiKey) {
|
|
293
|
+
throw new Error("Missing --apikey for fortnite-item-shop.");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const client = buildGamesClient(parsed);
|
|
297
|
+
const result = await client.getFortniteItemShop();
|
|
298
|
+
if (parsed.json) {
|
|
299
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
300
|
+
} else {
|
|
301
|
+
const data = result && result.data ? result.data : {};
|
|
302
|
+
const date = data.date || "unknown";
|
|
303
|
+
const entries = Array.isArray(data.entries) ? data.entries.length : 0;
|
|
304
|
+
process.stdout.write(`date=${date} entries=${entries}\n`);
|
|
305
|
+
}
|
|
306
|
+
return 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async function runWynncraftProfileCommand(parsed) {
|
|
310
|
+
const username = parsed.username || parsed.url;
|
|
311
|
+
|
|
312
|
+
if (!username) {
|
|
313
|
+
throw new Error("Missing --username for wynncraft-profile.");
|
|
314
|
+
}
|
|
315
|
+
if (!parsed.apiKey) {
|
|
316
|
+
throw new Error("Missing --apikey for wynncraft-profile.");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const client = buildGamesClient(parsed);
|
|
320
|
+
const result = await client.getWynncraftProfile(username);
|
|
321
|
+
if (parsed.json) {
|
|
322
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
323
|
+
} else {
|
|
324
|
+
process.stdout.write(`${result.username || username} online=${String(Boolean(result.online))}\n`);
|
|
325
|
+
}
|
|
326
|
+
return 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function runHypixelProfileCommand(parsed) {
|
|
330
|
+
const username = parsed.username || parsed.url;
|
|
331
|
+
|
|
332
|
+
if (!username) {
|
|
333
|
+
throw new Error("Missing --username for hypixel-profile.");
|
|
334
|
+
}
|
|
335
|
+
if (!parsed.apiKey) {
|
|
336
|
+
throw new Error("Missing --apikey for hypixel-profile.");
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const client = buildGamesClient(parsed);
|
|
340
|
+
const result = await client.getHypixelProfile(username);
|
|
341
|
+
if (parsed.json) {
|
|
342
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
343
|
+
} else {
|
|
344
|
+
const displayName = result.displayname || username;
|
|
345
|
+
const level = result.level || 0;
|
|
346
|
+
process.stdout.write(`${displayName} level=${level}\n`);
|
|
347
|
+
}
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
async function runRocketLeaguePlayerCommand(parsed) {
|
|
352
|
+
const username = parsed.username || parsed.url;
|
|
353
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
354
|
+
|
|
355
|
+
if (!username) {
|
|
356
|
+
throw new Error("Missing --username for rocketleague-player.");
|
|
357
|
+
}
|
|
358
|
+
if (!parsed.apiKey) {
|
|
359
|
+
throw new Error("Missing --apikey for rocketleague-player.");
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const client = buildGamesClient(parsed);
|
|
363
|
+
const result = await client.getRocketLeaguePlayer(username, platform);
|
|
364
|
+
if (parsed.json) {
|
|
365
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
366
|
+
} else {
|
|
367
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
368
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
369
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
370
|
+
}
|
|
371
|
+
return 0;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
async function runApexLegendsPlayerCommand(parsed) {
|
|
375
|
+
const username = parsed.username || parsed.url;
|
|
376
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
377
|
+
|
|
378
|
+
if (!username) {
|
|
379
|
+
throw new Error("Missing --username for apexlegends-player.");
|
|
380
|
+
}
|
|
381
|
+
if (!parsed.apiKey) {
|
|
382
|
+
throw new Error("Missing --apikey for apexlegends-player.");
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const client = buildGamesClient(parsed);
|
|
386
|
+
const result = await client.getApexLegendsPlayer(username, platform);
|
|
387
|
+
if (parsed.json) {
|
|
388
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
389
|
+
} else {
|
|
390
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
391
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
392
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
393
|
+
}
|
|
394
|
+
return 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async function runBattlefield1PlayerCommand(parsed) {
|
|
398
|
+
const username = parsed.username || parsed.url;
|
|
399
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
400
|
+
|
|
401
|
+
if (!username) {
|
|
402
|
+
throw new Error("Missing --username for battlefield1-player.");
|
|
403
|
+
}
|
|
404
|
+
if (!parsed.apiKey) {
|
|
405
|
+
throw new Error("Missing --apikey for battlefield1-player.");
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const client = buildGamesClient(parsed);
|
|
409
|
+
const result = await client.getBattlefield1Player(username, platform);
|
|
410
|
+
if (parsed.json) {
|
|
411
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
412
|
+
} else {
|
|
413
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
414
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
415
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
416
|
+
}
|
|
417
|
+
return 0;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
async function runBattlefield5PlayerCommand(parsed) {
|
|
421
|
+
const username = parsed.username || parsed.url;
|
|
422
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
423
|
+
|
|
424
|
+
if (!username) {
|
|
425
|
+
throw new Error("Missing --username for battlefield5-player.");
|
|
426
|
+
}
|
|
427
|
+
if (!parsed.apiKey) {
|
|
428
|
+
throw new Error("Missing --apikey for battlefield5-player.");
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const client = buildGamesClient(parsed);
|
|
432
|
+
const result = await client.getBattlefield5Player(username, platform);
|
|
433
|
+
if (parsed.json) {
|
|
434
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
435
|
+
} else {
|
|
436
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
437
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
438
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
439
|
+
}
|
|
440
|
+
return 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function runBattlefield2042PlayerCommand(parsed) {
|
|
444
|
+
const username = parsed.username || parsed.url;
|
|
445
|
+
const platform = parsed.divisionPlatform || parsed.platform || "ea";
|
|
446
|
+
|
|
447
|
+
if (!username) {
|
|
448
|
+
throw new Error("Missing --username for battlefield2042-player.");
|
|
449
|
+
}
|
|
450
|
+
if (!parsed.apiKey) {
|
|
451
|
+
throw new Error("Missing --apikey for battlefield2042-player.");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const client = buildGamesClient(parsed);
|
|
455
|
+
const result = await client.getBattlefield2042Player(username, platform);
|
|
456
|
+
if (parsed.json) {
|
|
457
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
458
|
+
} else {
|
|
459
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
460
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
461
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
462
|
+
}
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
async function runBattlefield6PlayerCommand(parsed) {
|
|
467
|
+
const username = parsed.username || parsed.url;
|
|
468
|
+
const platform = parsed.divisionPlatform || parsed.platform || "psn";
|
|
469
|
+
|
|
470
|
+
if (!username) {
|
|
471
|
+
throw new Error("Missing --username for battlefield6-player.");
|
|
472
|
+
}
|
|
473
|
+
if (!parsed.apiKey) {
|
|
474
|
+
throw new Error("Missing --apikey for battlefield6-player.");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
const client = buildGamesClient(parsed);
|
|
478
|
+
const result = await client.getBattlefield6Player(username, platform);
|
|
479
|
+
if (parsed.json) {
|
|
480
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
481
|
+
} else {
|
|
482
|
+
const source = result && result.profile && result.profile.data ? result.profile.data : null;
|
|
483
|
+
const handle = source && source.platformInfo ? source.platformInfo.platformUserHandle : username;
|
|
484
|
+
process.stdout.write(`${handle} platform=${platform}\n`);
|
|
485
|
+
}
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async function runDownloadJobCreateCommand(parsed, mode) {
|
|
490
|
+
if (!parsed.url) {
|
|
491
|
+
throw new Error(`Missing --url for download-${mode}.`);
|
|
492
|
+
}
|
|
493
|
+
if (!parsed.apiKey) {
|
|
494
|
+
throw new Error(`Missing --apikey for download-${mode}.`);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const downloader = buildDownloaderClient(parsed);
|
|
498
|
+
const createFn = mode === "mp3" ? downloader.createMp3Job.bind(downloader) : downloader.createMp4Job.bind(downloader);
|
|
499
|
+
const job = await createFn(parsed.url, {
|
|
500
|
+
uploadDest: parsed.uploadDest || "cdn"
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
if (parsed.wait) {
|
|
504
|
+
const finalState = await downloader.waitForJob(job.jobId, {
|
|
505
|
+
intervalMs: parsed.intervalMs || 2000,
|
|
506
|
+
timeoutMs: parsed.timeoutMs || 300000,
|
|
507
|
+
onProgress: (state) => {
|
|
508
|
+
const label = (state.upload && state.upload.label) || state.status || "working";
|
|
509
|
+
process.stdout.write(`[job ${state.job_id}] ${label}\n`);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
if (parsed.json) {
|
|
514
|
+
process.stdout.write(`${JSON.stringify({ job, final: finalState }, null, 2)}\n`);
|
|
515
|
+
} else {
|
|
516
|
+
process.stdout.write(`job_id=${job.jobId}\n`);
|
|
517
|
+
process.stdout.write(`status=${finalState.status}\n`);
|
|
518
|
+
if (finalState.url) {
|
|
519
|
+
process.stdout.write(`${finalState.url}\n`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return 0;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (parsed.json) {
|
|
526
|
+
process.stdout.write(`${JSON.stringify(job, null, 2)}\n`);
|
|
527
|
+
} else {
|
|
528
|
+
process.stdout.write(`${job.jobId}\n`);
|
|
529
|
+
}
|
|
530
|
+
return 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
async function runDownloadJobStatusCommand(parsed) {
|
|
534
|
+
if (!parsed.jobId) {
|
|
535
|
+
throw new Error("Missing --job-id for download-job.");
|
|
536
|
+
}
|
|
537
|
+
if (!parsed.apiKey) {
|
|
538
|
+
throw new Error("Missing --apikey for download-job.");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const downloader = buildDownloaderClient(parsed);
|
|
542
|
+
const state = await downloader.getJob(parsed.jobId);
|
|
543
|
+
if (parsed.json) {
|
|
544
|
+
process.stdout.write(`${JSON.stringify(state, null, 2)}\n`);
|
|
545
|
+
} else {
|
|
546
|
+
process.stdout.write(`status=${state.status || "unknown"}\n`);
|
|
547
|
+
if (state.url) {
|
|
548
|
+
process.stdout.write(`${state.url}\n`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return 0;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
async function runDownloadInfoCommand(parsed) {
|
|
555
|
+
if (!parsed.url) {
|
|
556
|
+
throw new Error("Missing --url for download-info.");
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const downloader = buildDownloaderClient(parsed);
|
|
560
|
+
const info = await downloader.getInfo(parsed.url, {
|
|
561
|
+
flat: parsed.flat,
|
|
562
|
+
fields: parsed.fields || "basic",
|
|
563
|
+
cache: typeof parsed.cache === "number" ? parsed.cache : 1
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
if (parsed.json) {
|
|
567
|
+
process.stdout.write(`${JSON.stringify(info, null, 2)}\n`);
|
|
568
|
+
} else {
|
|
569
|
+
process.stdout.write(`${info.title || info.id || "ok"}\n`);
|
|
570
|
+
}
|
|
571
|
+
return 0;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
async function runDownloadSearchCommand(parsed) {
|
|
575
|
+
if (!parsed.query) {
|
|
576
|
+
throw new Error("Missing --query for download-search.");
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const downloader = buildDownloaderClient(parsed);
|
|
580
|
+
const result = await downloader.searchYouTube(parsed.query, {
|
|
581
|
+
limit: parsed.limit || 5
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
if (parsed.json) {
|
|
585
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
586
|
+
} else {
|
|
587
|
+
const items = Array.isArray(result.items) ? result.items : [];
|
|
588
|
+
for (const item of items) {
|
|
589
|
+
process.stdout.write(`${item.title || "(no title)"} - ${item.url || ""}\n`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return 0;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async function runDownloadStreamUrlCommand(parsed) {
|
|
596
|
+
if (!parsed.url) {
|
|
597
|
+
throw new Error("Missing --url for download-stream-url.");
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const downloader = buildDownloaderClient(parsed);
|
|
601
|
+
const streamUrl = downloader.getStreamUrl(parsed.url);
|
|
602
|
+
process.stdout.write(`${streamUrl}\n`);
|
|
603
|
+
return 0;
|
|
604
|
+
}
|
|
605
|
+
|
|
34
606
|
async function runUploadCommand(parsed) {
|
|
35
607
|
const files = parsed.files;
|
|
36
608
|
if (files.length === 0) {
|
|
@@ -427,15 +999,82 @@ function parseArgs(argv) {
|
|
|
427
999
|
result.help = true;
|
|
428
1000
|
} else if (token === "--json") {
|
|
429
1001
|
result.json = true;
|
|
1002
|
+
} else if (token === "--wait") {
|
|
1003
|
+
result.wait = true;
|
|
1004
|
+
} else if (token === "--flat" || token === "--flat-playlist") {
|
|
1005
|
+
result.flat = true;
|
|
430
1006
|
} else if (token === "--file" || token === "-f") {
|
|
431
1007
|
const value = argv[i + 1];
|
|
432
1008
|
i += 1;
|
|
433
1009
|
if (value) {
|
|
434
1010
|
result.files.push(value);
|
|
435
1011
|
}
|
|
1012
|
+
} else if (token === "--username") {
|
|
1013
|
+
result.username = argv[i + 1];
|
|
1014
|
+
i += 1;
|
|
1015
|
+
} else if (token === "--stream-platform") {
|
|
1016
|
+
result.streamPlatform = argv[i + 1];
|
|
1017
|
+
i += 1;
|
|
1018
|
+
} else if (token === "--clan-tag") {
|
|
1019
|
+
result.clanTag = argv[i + 1];
|
|
1020
|
+
i += 1;
|
|
1021
|
+
} else if (token === "--player-tag") {
|
|
1022
|
+
result.playerTag = argv[i + 1];
|
|
1023
|
+
i += 1;
|
|
1024
|
+
} else if (token === "--tag") {
|
|
1025
|
+
result.tag = argv[i + 1];
|
|
1026
|
+
i += 1;
|
|
1027
|
+
} else if (token === "--livestream-preset") {
|
|
1028
|
+
result.livestreamPreset = argv[i + 1];
|
|
1029
|
+
i += 1;
|
|
1030
|
+
} else if (token === "--livestream-base-url") {
|
|
1031
|
+
result.livestreamBaseUrl = argv[i + 1];
|
|
1032
|
+
i += 1;
|
|
1033
|
+
} else if (token === "--games-preset") {
|
|
1034
|
+
result.gamesPreset = argv[i + 1];
|
|
1035
|
+
i += 1;
|
|
1036
|
+
} else if (token === "--games-base-url") {
|
|
1037
|
+
result.gamesBaseUrl = argv[i + 1];
|
|
1038
|
+
i += 1;
|
|
1039
|
+
} else if (token === "--division-platform" || token === "--game-platform") {
|
|
1040
|
+
result.divisionPlatform = argv[i + 1];
|
|
1041
|
+
i += 1;
|
|
1042
|
+
} else if (token === "--time-window") {
|
|
1043
|
+
result.timeWindow = argv[i + 1];
|
|
1044
|
+
i += 1;
|
|
1045
|
+
} else if (token === "--creator-code" || token === "--code") {
|
|
1046
|
+
result.creatorCode = argv[i + 1];
|
|
1047
|
+
i += 1;
|
|
436
1048
|
} else if (token === "--url") {
|
|
437
1049
|
result.url = argv[i + 1];
|
|
438
1050
|
i += 1;
|
|
1051
|
+
} else if (token === "--job-id") {
|
|
1052
|
+
result.jobId = argv[i + 1];
|
|
1053
|
+
i += 1;
|
|
1054
|
+
} else if (token === "--query" || token === "-q") {
|
|
1055
|
+
result.query = argv[i + 1];
|
|
1056
|
+
i += 1;
|
|
1057
|
+
} else if (token === "--limit") {
|
|
1058
|
+
result.limit = Number(argv[i + 1]);
|
|
1059
|
+
i += 1;
|
|
1060
|
+
} else if (token === "--fields") {
|
|
1061
|
+
result.fields = argv[i + 1];
|
|
1062
|
+
i += 1;
|
|
1063
|
+
} else if (token === "--cache") {
|
|
1064
|
+
result.cache = Number(argv[i + 1]);
|
|
1065
|
+
i += 1;
|
|
1066
|
+
} else if (token === "--upload-dest") {
|
|
1067
|
+
result.uploadDest = argv[i + 1];
|
|
1068
|
+
i += 1;
|
|
1069
|
+
} else if (token === "--downloader-preset") {
|
|
1070
|
+
result.downloaderPreset = argv[i + 1];
|
|
1071
|
+
i += 1;
|
|
1072
|
+
} else if (token === "--downloader-base-url") {
|
|
1073
|
+
result.downloaderBaseUrl = argv[i + 1];
|
|
1074
|
+
i += 1;
|
|
1075
|
+
} else if (token === "--interval") {
|
|
1076
|
+
result.intervalMs = Number(argv[i + 1]);
|
|
1077
|
+
i += 1;
|
|
439
1078
|
} else if (token === "--platform" || token === "-p") {
|
|
440
1079
|
result.platform = argv[i + 1];
|
|
441
1080
|
i += 1;
|
|
@@ -498,20 +1137,93 @@ function parseArgs(argv) {
|
|
|
498
1137
|
|
|
499
1138
|
function printHelp() {
|
|
500
1139
|
const helpText = `
|
|
501
|
-
|
|
1140
|
+
nekosunevrtools CLI
|
|
502
1141
|
|
|
503
1142
|
Commands:
|
|
504
|
-
upload
|
|
505
|
-
shorten
|
|
506
|
-
upload-shorten
|
|
507
|
-
video-upload
|
|
508
|
-
|
|
1143
|
+
upload Upload files
|
|
1144
|
+
shorten Convert a URL into monetized short link
|
|
1145
|
+
upload-shorten Upload file then monetize resulting URL
|
|
1146
|
+
video-upload Upload video to video-earn provider
|
|
1147
|
+
download-mp3 Create MP3 download job
|
|
1148
|
+
download-mp4 Create MP4 download job
|
|
1149
|
+
download-job Get download job status
|
|
1150
|
+
download-info Fetch metadata for URL
|
|
1151
|
+
download-search Search YouTube
|
|
1152
|
+
download-stream-url Build /api/stream URL
|
|
1153
|
+
live-kick Get Kick livestream data
|
|
1154
|
+
live-twitch Get Twitch livestream data
|
|
1155
|
+
live-dlive Get DLive livestream data
|
|
1156
|
+
live-trovo Get Trovo livestream data
|
|
1157
|
+
live Get livestream data by --stream-platform
|
|
1158
|
+
coc-clan Get Clash of Clans clan by tag
|
|
1159
|
+
coc-player Get Clash of Clans player by tag
|
|
1160
|
+
division2-player Get The Division 2 player by username/platform
|
|
1161
|
+
td2-player Alias for division2-player
|
|
1162
|
+
fortnite-player Get Fortnite player by username/time window
|
|
1163
|
+
fn-player Alias for fortnite-player
|
|
1164
|
+
fortnite-creatorcode Get Fortnite creator code details
|
|
1165
|
+
fn-creatorcode Alias for fortnite-creatorcode
|
|
1166
|
+
fortnite-item-shop Get current Fortnite item shop
|
|
1167
|
+
fn-item-shop Alias for fortnite-item-shop
|
|
1168
|
+
wynncraft-profile Get Wynncraft profile by username
|
|
1169
|
+
wc-profile Alias for wynncraft-profile
|
|
1170
|
+
hypixel-profile Get Hypixel profile by username
|
|
1171
|
+
hp-profile Alias for hypixel-profile
|
|
1172
|
+
rocketleague-player Get Rocket League player by username/platform
|
|
1173
|
+
rl-player Alias for rocketleague-player
|
|
1174
|
+
apexlegends-player Get Apex Legends player by username/platform
|
|
1175
|
+
apex-player Alias for apexlegends-player
|
|
1176
|
+
battlefield1-player Get Battlefield 1 player by username/platform
|
|
1177
|
+
bf1-player Alias for battlefield1-player
|
|
1178
|
+
battlefield5-player Get Battlefield 5 player by username/platform
|
|
1179
|
+
bf5-player Alias for battlefield5-player
|
|
1180
|
+
battlefield2042-player Get Battlefield 2042 player by username/platform
|
|
1181
|
+
bf2042-player Alias for battlefield2042-player
|
|
1182
|
+
battlefield6-player Get Battlefield 6 player by username/platform
|
|
1183
|
+
bf6-player Alias for battlefield6-player
|
|
1184
|
+
list-shorteners Show built-in shortlink preset names
|
|
1185
|
+
list-download-presets Show downloader API host presets
|
|
1186
|
+
list-livestream-presets Show livestream API host presets
|
|
1187
|
+
list-games-presets Show games API host presets
|
|
509
1188
|
|
|
510
1189
|
Usage:
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
1190
|
+
nekosunevrtools download-mp3 --url <link> --apikey <key> [--upload-dest cdn]
|
|
1191
|
+
nekosunevrtools download-job --job-id <id> --apikey <key>
|
|
1192
|
+
nekosunevrtools live-kick --username mugstv --apikey YOUR_KEY
|
|
1193
|
+
nekosunevrtools coc-clan --clan-tag 2LLJYCUU8 --apikey YOUR_KEY
|
|
1194
|
+
|
|
1195
|
+
Downloader options:
|
|
1196
|
+
--downloader-preset <name> Host preset: nekosune|ballisticok (default: nekosune)
|
|
1197
|
+
--downloader-base-url <url> Custom compatible host base URL
|
|
1198
|
+
--upload-dest <name> cdn|thirdparty|ipfs
|
|
1199
|
+
--job-id <id> Job ID for status lookup
|
|
1200
|
+
--query, -q <text> Search query
|
|
1201
|
+
--limit <n> Search limit (1-25)
|
|
1202
|
+
--fields <basic|full> Info response fields
|
|
1203
|
+
--flat Use flat playlist mode
|
|
1204
|
+
--cache <0|1> Info cache toggle
|
|
1205
|
+
--wait Poll job until done
|
|
1206
|
+
--interval <ms> Poll interval (default: 2000)
|
|
1207
|
+
--url <url> Target URL/link
|
|
1208
|
+
--apikey, --api-key, -k API key for secured endpoints
|
|
1209
|
+
|
|
1210
|
+
Livestream options:
|
|
1211
|
+
--username <name> Streamer username
|
|
1212
|
+
--stream-platform <name> kick|twitch|dlive|trovo (used with live)
|
|
1213
|
+
--livestream-preset <name> API host preset (default: nekosune)
|
|
1214
|
+
--livestream-base-url <url> Custom API base URL
|
|
1215
|
+
|
|
1216
|
+
Games options:
|
|
1217
|
+
--clan-tag <tag> Clash of Clans clan tag
|
|
1218
|
+
--player-tag <tag> Clash of Clans player tag
|
|
1219
|
+
--tag <tag> Generic tag alias
|
|
1220
|
+
--username <name> Game username (varies by endpoint)
|
|
1221
|
+
--division-platform <name> Game platform for supported commands (default: psn)
|
|
1222
|
+
--game-platform <name> Alias for --division-platform
|
|
1223
|
+
--time-window <name> Fortnite stats window (default: lifetime)
|
|
1224
|
+
--creator-code <value> Fortnite creator code
|
|
1225
|
+
--games-preset <name> API host preset (default: nekosune)
|
|
1226
|
+
--games-base-url <url> Custom API base URL
|
|
515
1227
|
|
|
516
1228
|
Shared options:
|
|
517
1229
|
--json JSON output
|
|
@@ -520,7 +1232,6 @@ Shared options:
|
|
|
520
1232
|
Upload options:
|
|
521
1233
|
--platform, -p <name> Platform: upfiles|fileio|catbox|transfersh (default: upfiles)
|
|
522
1234
|
--file, -f <path> File path (repeatable)
|
|
523
|
-
--apikey, --api-key, -k API key for provider
|
|
524
1235
|
--expires <value> file.io expiration metadata (example: 1w)
|
|
525
1236
|
--meta key=value Additional metadata field (repeatable)
|
|
526
1237
|
--retry, --retries, -r <n> Retry count per file (default: 0)
|
|
@@ -528,7 +1239,6 @@ Upload options:
|
|
|
528
1239
|
--timeout <ms> Request timeout in milliseconds (default: 60000)
|
|
529
1240
|
|
|
530
1241
|
Short-link options:
|
|
531
|
-
--url <url> URL to shorten
|
|
532
1242
|
--shortener-preset <name> Preset from list-shorteners
|
|
533
1243
|
--base-url <url> Custom AdLinkFly-compatible API base URL
|
|
534
1244
|
--shortener-apikey <key> API key for shortener (or reuse --apikey)
|
|
@@ -544,7 +1254,11 @@ Discord progress options:
|
|
|
544
1254
|
`;
|
|
545
1255
|
process.stdout.write(helpText);
|
|
546
1256
|
}
|
|
547
|
-
|
|
548
1257
|
module.exports = {
|
|
549
1258
|
runCli
|
|
550
1259
|
};
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
|