feat: add monitor mode
parent
1a08202ae2
commit
e3a037dcac
3
s3si.ts
3
s3si.ts
|
|
@ -5,12 +5,13 @@ import { flags } from "./deps.ts";
|
||||||
const parseArgs = (args: string[]) => {
|
const parseArgs = (args: string[]) => {
|
||||||
const parsed = flags.parse(args, {
|
const parsed = flags.parse(args, {
|
||||||
string: ["profilePath", "exporter"],
|
string: ["profilePath", "exporter"],
|
||||||
boolean: ["help", "noProgress"],
|
boolean: ["help", "noProgress", "monitor"],
|
||||||
alias: {
|
alias: {
|
||||||
"help": "h",
|
"help": "h",
|
||||||
"profilePath": ["p", "profile-path"],
|
"profilePath": ["p", "profile-path"],
|
||||||
"exporter": ["e"],
|
"exporter": ["e"],
|
||||||
"noProgress": ["n", "no-progress"],
|
"noProgress": ["n", "no-progress"],
|
||||||
|
"monitor": ["m"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|
|
||||||
137
src/app.ts
137
src/app.ts
|
|
@ -17,7 +17,7 @@ import {
|
||||||
import { Cache, FileCache, MemoryCache } from "./cache.ts";
|
import { Cache, FileCache, MemoryCache } from "./cache.ts";
|
||||||
import { StatInkExporter } from "./exporters/stat.ink.ts";
|
import { StatInkExporter } from "./exporters/stat.ink.ts";
|
||||||
import { FileExporter } from "./exporters/file.ts";
|
import { FileExporter } from "./exporters/file.ts";
|
||||||
import { battleId, readline, showError } from "./utils.ts";
|
import { battleId, delay, readline, showError } from "./utils.ts";
|
||||||
|
|
||||||
export type Opts = {
|
export type Opts = {
|
||||||
profilePath: string;
|
profilePath: string;
|
||||||
|
|
@ -200,7 +200,12 @@ export class App {
|
||||||
statInkApiKey: key,
|
statInkApiKey: key,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
out.push(new StatInkExporter(this.state.statInkApiKey!));
|
out.push(
|
||||||
|
new StatInkExporter(
|
||||||
|
this.state.statInkApiKey!,
|
||||||
|
this.opts.monitor ? "Monitoring" : "Manual",
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exporters.includes("file")) {
|
if (exporters.includes("file")) {
|
||||||
|
|
@ -209,58 +214,16 @@ export class App {
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
async run() {
|
async exportOnce() {
|
||||||
await this.readState();
|
|
||||||
|
|
||||||
const bar = !this.opts.noProgress
|
const bar = !this.opts.noProgress
|
||||||
? new MultiProgressBar({
|
? new MultiProgressBar({
|
||||||
title: "Export battles",
|
title: "Export battles",
|
||||||
display: "[:bar] :text :percent :time eta: :eta :completed/:total",
|
display: "[:bar] :text :percent :time eta: :eta :completed/:total",
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const exporters = await this.getExporters();
|
const exporters = await this.getExporters();
|
||||||
|
|
||||||
if (!this.state.loginState?.sessionToken) {
|
|
||||||
const sessionToken = await loginManually();
|
|
||||||
|
|
||||||
await this.writeState({
|
|
||||||
...this.state,
|
|
||||||
loginState: {
|
|
||||||
...this.state.loginState,
|
|
||||||
sessionToken,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const sessionToken = this.state.loginState!.sessionToken!;
|
|
||||||
|
|
||||||
console.log("Checking token...");
|
|
||||||
if (!await checkToken(this.state)) {
|
|
||||||
console.log("Token expired, refetch tokens.");
|
|
||||||
|
|
||||||
const { webServiceToken, userCountry, userLang } = await getGToken({
|
|
||||||
fApi: this.state.fGen,
|
|
||||||
sessionToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
const bulletToken = await getBulletToken({
|
|
||||||
webServiceToken,
|
|
||||||
userLang,
|
|
||||||
userCountry,
|
|
||||||
appUserAgent: this.state.appUserAgent,
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.writeState({
|
|
||||||
...this.state,
|
|
||||||
loginState: {
|
|
||||||
...this.state.loginState,
|
|
||||||
gToken: webServiceToken,
|
|
||||||
bulletToken,
|
|
||||||
},
|
|
||||||
userLang: this.state.userLang ?? userLang,
|
|
||||||
userCountry: this.state.userCountry ?? userCountry,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const fetcher = new BattleFetcher({
|
const fetcher = new BattleFetcher({
|
||||||
cache: new FileCache(this.state.cacheDir),
|
cache: new FileCache(this.state.cacheDir),
|
||||||
state: this.state,
|
state: this.state,
|
||||||
|
|
@ -302,7 +265,87 @@ export class App {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log("\nDone.", stats);
|
bar?.end();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`Exported ${
|
||||||
|
Object.entries(stats)
|
||||||
|
.map(([name, count]) => `${name}: ${count}`)
|
||||||
|
.join(", ")
|
||||||
|
}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async monitor() {
|
||||||
|
while (true) {
|
||||||
|
await this.exportOnce();
|
||||||
|
await this.countDown(this.state.monitorInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async countDown(sec: number) {
|
||||||
|
const bar = !this.opts.noProgress
|
||||||
|
? new MultiProgressBar({
|
||||||
|
title: "Killing time...",
|
||||||
|
display: "[:bar] :completed/:total",
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
for (const i of Array(sec).keys()) {
|
||||||
|
bar?.render([{
|
||||||
|
completed: i,
|
||||||
|
total: sec,
|
||||||
|
}]);
|
||||||
|
await delay(1000);
|
||||||
|
}
|
||||||
|
bar?.end();
|
||||||
|
}
|
||||||
|
async run() {
|
||||||
|
await this.readState();
|
||||||
|
|
||||||
|
if (!this.state.loginState?.sessionToken) {
|
||||||
|
const sessionToken = await loginManually();
|
||||||
|
|
||||||
|
await this.writeState({
|
||||||
|
...this.state,
|
||||||
|
loginState: {
|
||||||
|
...this.state.loginState,
|
||||||
|
sessionToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const sessionToken = this.state.loginState!.sessionToken!;
|
||||||
|
|
||||||
|
console.log("Checking token...");
|
||||||
|
if (!await checkToken(this.state)) {
|
||||||
|
console.log("Token expired, refetch tokens.");
|
||||||
|
|
||||||
|
const { webServiceToken, userCountry, userLang } = await getGToken({
|
||||||
|
fApi: this.state.fGen,
|
||||||
|
sessionToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
const bulletToken = await getBulletToken({
|
||||||
|
webServiceToken,
|
||||||
|
userLang,
|
||||||
|
userCountry,
|
||||||
|
appUserAgent: this.state.appUserAgent,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.writeState({
|
||||||
|
...this.state,
|
||||||
|
loginState: {
|
||||||
|
...this.state.loginState,
|
||||||
|
gToken: webServiceToken,
|
||||||
|
bulletToken,
|
||||||
|
},
|
||||||
|
userLang: this.state.userLang ?? userLang,
|
||||||
|
userCountry: this.state.userCountry ?? userCountry,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.opts.monitor) {
|
||||||
|
await this.monitor();
|
||||||
|
} else {
|
||||||
|
await this.exportOnce();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Export battle list.
|
* Export battle list.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import type { StatInkPostBody, VsHistoryDetail } from "./types.ts";
|
import type { StatInkPostBody, VsHistoryDetail } from "./types.ts";
|
||||||
|
|
||||||
export const AGENT_NAME = "s3si.ts";
|
export const AGENT_NAME = "s3si.ts";
|
||||||
export const S3SI_VERSION = "0.1.5";
|
export const S3SI_VERSION = "0.1.6";
|
||||||
export const NSOAPP_VERSION = "2.3.1";
|
export const NSOAPP_VERSION = "2.3.1";
|
||||||
export const WEB_VIEW_VERSION = "1.0.0-216d0219";
|
export const WEB_VIEW_VERSION = "1.0.0-216d0219";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ const getStage = cache(_getStage);
|
||||||
*/
|
*/
|
||||||
export class StatInkExporter implements BattleExporter<VsBattle> {
|
export class StatInkExporter implements BattleExporter<VsBattle> {
|
||||||
name = "stat.ink";
|
name = "stat.ink";
|
||||||
constructor(private statInkApiKey: string) {
|
|
||||||
|
constructor(private statInkApiKey: string, private uploadMode: string) {
|
||||||
if (statInkApiKey.length !== 43) {
|
if (statInkApiKey.length !== 43) {
|
||||||
throw new Error("Invalid stat.ink API key");
|
throw new Error("Invalid stat.ink API key");
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +204,9 @@ export class StatInkExporter implements BattleExporter<VsBattle> {
|
||||||
|
|
||||||
agent: AGENT_NAME,
|
agent: AGENT_NAME,
|
||||||
agent_version: S3SI_VERSION,
|
agent_version: S3SI_VERSION,
|
||||||
agent_variables: undefined,
|
agent_variables: {
|
||||||
|
"Upload Mode": this.uploadMode,
|
||||||
|
},
|
||||||
automated: "yes",
|
automated: "yes",
|
||||||
start_at: startedAt,
|
start_at: startedAt,
|
||||||
end_at: startedAt + vsDetail.duration,
|
end_at: startedAt + vsDetail.duration,
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,12 @@ export type State = {
|
||||||
// Exporter config
|
// Exporter config
|
||||||
statInkApiKey?: string;
|
statInkApiKey?: string;
|
||||||
fileExportPath: string;
|
fileExportPath: string;
|
||||||
|
monitorInterval: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_STATE: State = {
|
export const DEFAULT_STATE: State = {
|
||||||
cacheDir: "./cache",
|
cacheDir: "./cache",
|
||||||
fGen: "https://api.imink.app/f",
|
fGen: "https://api.imink.app/f",
|
||||||
fileExportPath: "./export",
|
fileExportPath: "./export",
|
||||||
|
monitorInterval: 500,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -113,3 +113,6 @@ export function parseVsHistoryDetailId(id: string) {
|
||||||
uuid,
|
uuid,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const delay = (ms: number) =>
|
||||||
|
new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue