From a63426a2823f77c5c12d66b3276487c75bfcece8 Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Fri, 21 Oct 2022 19:09:30 +0800 Subject: [PATCH 1/5] refactor: move sources to src --- s3si.ts | 355 +----------------------- APIError.ts => src/APIError.ts | 0 src/app.ts | 352 +++++++++++++++++++++++ cache.ts => src/cache.ts | 2 +- constant.ts => src/constant.ts | 0 {exporter => src/exporters}/file.ts | 2 +- {exporter => src/exporters}/stat.ink.ts | 2 +- iksm.ts => src/iksm.ts | 2 +- splatnet3.ts => src/splatnet3.ts | 0 state.ts => src/state.ts | 0 types.ts => src/types.ts | 0 utils.ts => src/utils.ts | 2 +- 12 files changed, 360 insertions(+), 357 deletions(-) rename APIError.ts => src/APIError.ts (100%) create mode 100644 src/app.ts rename cache.ts => src/cache.ts (97%) rename constant.ts => src/constant.ts (100%) rename {exporter => src/exporters}/file.ts (97%) rename {exporter => src/exporters}/stat.ink.ts (99%) rename iksm.ts => src/iksm.ts (99%) rename splatnet3.ts => src/splatnet3.ts (100%) rename state.ts => src/state.ts (100%) rename types.ts => src/types.ts (100%) rename utils.ts => src/utils.ts (97%) diff --git a/s3si.ts b/s3si.ts index f658e69..97ca267 100644 --- a/s3si.ts +++ b/s3si.ts @@ -1,355 +1,6 @@ -import { getBulletToken, getGToken, loginManually } from "./iksm.ts"; -import { flags, MultiProgressBar, Mutex } from "./deps.ts"; -import { DEFAULT_STATE, State } from "./state.ts"; -import { - checkToken, - getBankaraBattleHistories, - getBattleDetail, - getBattleList, -} from "./splatnet3.ts"; -import { - BattleExporter, - HistoryGroups, - VsBattle, - VsHistoryDetail, -} from "./types.ts"; -import { Cache, FileCache, MemoryCache } from "./cache.ts"; -import { StatInkExporter } from "./exporter/stat.ink.ts"; -import { battleId, readline, showError } from "./utils.ts"; -import { FileExporter } from "./exporter/file.ts"; - -type Opts = { - profilePath: string; - exporter: string; - noProgress: boolean; - help?: boolean; -}; - -const DEFAULT_OPTS: Opts = { - profilePath: "./profile.json", - exporter: "stat.ink", - noProgress: false, - help: false, -}; - -/** - * Fetch battle and cache it. - */ -class BattleFetcher { - state: State; - cache: Cache; - lock: Record = {}; - bankaraLock = new Mutex(); - bankaraHistory?: HistoryGroups["nodes"]; - - constructor( - { cache = new MemoryCache(), state }: { state: State; cache?: Cache }, - ) { - this.state = state; - this.cache = cache; - } - private async getLock(id: string): Promise { - const bid = await battleId(id); - - let cur = this.lock[bid]; - if (!cur) { - cur = new Mutex(); - this.lock[bid] = cur; - } - - return cur; - } - getBankaraHistory() { - return this.bankaraLock.use(async () => { - if (this.bankaraHistory) { - return this.bankaraHistory; - } - - const { bankaraBattleHistories: { historyGroups } } = - await getBankaraBattleHistories( - this.state, - ); - - this.bankaraHistory = historyGroups.nodes; - - return this.bankaraHistory; - }); - } - async getBattleMetaById(id: string): Promise> { - const bid = await battleId(id); - const bankaraHistory = await this.getBankaraHistory(); - const group = bankaraHistory.find((i) => - i.historyDetails.nodes.some((i) => i._bid === bid) - ); - - if (!group) { - return { - bankaraMatchChallenge: null, - listNode: null, - }; - } - - const { bankaraMatchChallenge } = group; - const listNode = group.historyDetails.nodes.find((i) => i._bid === bid) ?? - null; - - return { - bankaraMatchChallenge, - listNode, - }; - } - async getBattleDetail(id: string): Promise { - const lock = await this.getLock(id); - - return lock.use(async () => { - const cached = await this.cache.read(id); - if (cached) { - return cached; - } - - const detail = (await getBattleDetail(this.state, id)) - .vsHistoryDetail; - - await this.cache.write(id, detail); - - return detail; - }); - } - async fetchBattle(id: string): Promise { - const detail = await this.getBattleDetail(id); - const metadata = await this.getBattleMetaById(id); - - const battle: VsBattle = { - ...metadata, - detail, - }; - - return battle; - } -} - -type Progress = { - current: number; - total: number; -}; - -class App { - state: State = DEFAULT_STATE; - - constructor(public opts: Opts) { - if (this.opts.help) { - console.log( - `Usage: deno run -A ${Deno.mainModule} [options] - -Options: - --profile-path , -p Path to config file (default: ./profile.json) - --exporter , -e Exporter list to use (default: stat.ink) - Multiple exporters can be separated by commas - (e.g. "stat.ink,file") - --no-progress, -n Disable progress bar - --help Show this help message and exit`, - ); - Deno.exit(0); - } - } - async writeState(newState: State) { - this.state = newState; - const encoder = new TextEncoder(); - const data = encoder.encode(JSON.stringify(this.state, undefined, 2)); - const swapPath = `${this.opts.profilePath}.swap`; - await Deno.writeFile(swapPath, data); - await Deno.rename(swapPath, this.opts.profilePath); - } - async readState() { - const decoder = new TextDecoder(); - try { - const data = await Deno.readFile(this.opts.profilePath); - const json = JSON.parse(decoder.decode(data)); - this.state = { - ...DEFAULT_STATE, - ...json, - }; - } catch (e) { - console.warn( - `Failed to read config file, create new config file. (${e})`, - ); - await this.writeState(DEFAULT_STATE); - } - } - async getExporters(): Promise[]> { - const exporters = this.opts.exporter.split(","); - const out: BattleExporter[] = []; - - if (exporters.includes("stat.ink")) { - if (!this.state.statInkApiKey) { - console.log("stat.ink API key is not set. Please enter below."); - const key = (await readline()).trim(); - if (!key) { - console.error("API key is required."); - Deno.exit(1); - } - await this.writeState({ - ...this.state, - statInkApiKey: key, - }); - } - out.push(new StatInkExporter(this.state.statInkApiKey!)); - } - - if (exporters.includes("file")) { - out.push(new FileExporter(this.state.fileExportPath)); - } - - return out; - } - async run() { - await this.readState(); - - const bar = !this.opts.noProgress - ? new MultiProgressBar({ - title: "Export battles", - display: "[:bar] :text :percent :time eta: :eta :completed/:total", - }) - : undefined; - 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({ - cache: new FileCache(this.state.cacheDir), - state: this.state, - }); - console.log("Fetching battle list..."); - const battleList = await getBattleList(this.state); - - const allProgress: Record = {}; - const redraw = (name: string, progress: Progress) => { - allProgress[name] = progress; - bar?.render( - Object.entries(allProgress).map(([name, progress]) => ({ - completed: progress.current, - total: progress.total, - text: name, - })), - ); - }; - const stats: Record = Object.fromEntries( - exporters.map((e) => [e.name, 0]), - ); - - await Promise.all( - exporters.map((e) => - showError( - this.exportBattleList({ - fetcher, - exporter: e, - battleList, - onStep: (progress) => redraw(e.name, progress), - }) - .then((count) => { - stats[e.name] = count; - }), - ) - .catch((err) => { - console.error(`\nFailed to export to ${e.name}:`, err); - }) - ), - ); - - console.log("\nDone.", stats); - } - /** - * Export battle list. - * - * @param fetcher BattleFetcher - * @param exporter BattleExporter - * @param battleList ID list of battles, sorted by date, newest first - * @param onStep Callback function called when a battle is exported - */ - async exportBattleList( - { - fetcher, - exporter, - battleList, - onStep, - }: { - fetcher: BattleFetcher; - exporter: BattleExporter; - battleList: string[]; - onStep?: (progress: Progress) => void; - }, - ): Promise { - let exported = 0; - - onStep?.({ - current: 0, - total: 1, - }); - - const workQueue = [...await exporter.notExported(battleList)].reverse(); - - const step = async (battle: string) => { - const detail = await fetcher.fetchBattle(battle); - await exporter.exportBattle(detail); - exported += 1; - onStep?.({ - current: exported, - total: workQueue.length, - }); - }; - - if (workQueue.length > 0) { - onStep?.({ - current: exported, - total: workQueue.length, - }); - for (const battle of workQueue) { - await step(battle); - } - } - - return exported; - } -} +import { App, DEFAULT_OPTS } from "./src/app.ts"; +import { showError } from "./src/utils.ts"; +import { flags } from "./deps.ts"; const parseArgs = (args: string[]) => { const parsed = flags.parse(args, { diff --git a/APIError.ts b/src/APIError.ts similarity index 100% rename from APIError.ts rename to src/APIError.ts diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..a994008 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,352 @@ +import { getBulletToken, getGToken, loginManually } from "./iksm.ts"; +import { MultiProgressBar, Mutex } from "../deps.ts"; +import { DEFAULT_STATE, State } from "./state.ts"; +import { + checkToken, + getBankaraBattleHistories, + getBattleDetail, + getBattleList, +} from "./splatnet3.ts"; +import { + BattleExporter, + HistoryGroups, + VsBattle, + VsHistoryDetail, +} from "./types.ts"; +import { Cache, FileCache, MemoryCache } from "./cache.ts"; +import { StatInkExporter } from "./exporters/stat.ink.ts"; +import { FileExporter } from "./exporters/file.ts"; +import { battleId, readline, showError } from "./utils.ts"; + +export type Opts = { + profilePath: string; + exporter: string; + noProgress: boolean; + help?: boolean; +}; + +export const DEFAULT_OPTS: Opts = { + profilePath: "./profile.json", + exporter: "stat.ink", + noProgress: false, + help: false, +}; + +/** + * Fetch battle and cache it. + */ +class BattleFetcher { + state: State; + cache: Cache; + lock: Record = {}; + bankaraLock = new Mutex(); + bankaraHistory?: HistoryGroups["nodes"]; + + constructor( + { cache = new MemoryCache(), state }: { state: State; cache?: Cache }, + ) { + this.state = state; + this.cache = cache; + } + private async getLock(id: string): Promise { + const bid = await battleId(id); + + let cur = this.lock[bid]; + if (!cur) { + cur = new Mutex(); + this.lock[bid] = cur; + } + + return cur; + } + getBankaraHistory() { + return this.bankaraLock.use(async () => { + if (this.bankaraHistory) { + return this.bankaraHistory; + } + + const { bankaraBattleHistories: { historyGroups } } = + await getBankaraBattleHistories( + this.state, + ); + + this.bankaraHistory = historyGroups.nodes; + + return this.bankaraHistory; + }); + } + async getBattleMetaById(id: string): Promise> { + const bid = await battleId(id); + const bankaraHistory = await this.getBankaraHistory(); + const group = bankaraHistory.find((i) => + i.historyDetails.nodes.some((i) => i._bid === bid) + ); + + if (!group) { + return { + bankaraMatchChallenge: null, + listNode: null, + }; + } + + const { bankaraMatchChallenge } = group; + const listNode = group.historyDetails.nodes.find((i) => i._bid === bid) ?? + null; + + return { + bankaraMatchChallenge, + listNode, + }; + } + async getBattleDetail(id: string): Promise { + const lock = await this.getLock(id); + + return lock.use(async () => { + const cached = await this.cache.read(id); + if (cached) { + return cached; + } + + const detail = (await getBattleDetail(this.state, id)) + .vsHistoryDetail; + + await this.cache.write(id, detail); + + return detail; + }); + } + async fetchBattle(id: string): Promise { + const detail = await this.getBattleDetail(id); + const metadata = await this.getBattleMetaById(id); + + const battle: VsBattle = { + ...metadata, + detail, + }; + + return battle; + } +} + +type Progress = { + current: number; + total: number; +}; + +export class App { + state: State = DEFAULT_STATE; + + constructor(public opts: Opts) { + if (this.opts.help) { + console.log( + `Usage: deno run -A ${Deno.mainModule} [options] + +Options: + --profile-path , -p Path to config file (default: ./profile.json) + --exporter , -e Exporter list to use (default: stat.ink) + Multiple exporters can be separated by commas + (e.g. "stat.ink,file") + --no-progress, -n Disable progress bar + --help Show this help message and exit`, + ); + Deno.exit(0); + } + } + async writeState(newState: State) { + this.state = newState; + const encoder = new TextEncoder(); + const data = encoder.encode(JSON.stringify(this.state, undefined, 2)); + const swapPath = `${this.opts.profilePath}.swap`; + await Deno.writeFile(swapPath, data); + await Deno.rename(swapPath, this.opts.profilePath); + } + async readState() { + const decoder = new TextDecoder(); + try { + const data = await Deno.readFile(this.opts.profilePath); + const json = JSON.parse(decoder.decode(data)); + this.state = { + ...DEFAULT_STATE, + ...json, + }; + } catch (e) { + console.warn( + `Failed to read config file, create new config file. (${e})`, + ); + await this.writeState(DEFAULT_STATE); + } + } + async getExporters(): Promise[]> { + const exporters = this.opts.exporter.split(","); + const out: BattleExporter[] = []; + + if (exporters.includes("stat.ink")) { + if (!this.state.statInkApiKey) { + console.log("stat.ink API key is not set. Please enter below."); + const key = (await readline()).trim(); + if (!key) { + console.error("API key is required."); + Deno.exit(1); + } + await this.writeState({ + ...this.state, + statInkApiKey: key, + }); + } + out.push(new StatInkExporter(this.state.statInkApiKey!)); + } + + if (exporters.includes("file")) { + out.push(new FileExporter(this.state.fileExportPath)); + } + + return out; + } + async run() { + await this.readState(); + + const bar = !this.opts.noProgress + ? new MultiProgressBar({ + title: "Export battles", + display: "[:bar] :text :percent :time eta: :eta :completed/:total", + }) + : undefined; + 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({ + cache: new FileCache(this.state.cacheDir), + state: this.state, + }); + console.log("Fetching battle list..."); + const battleList = await getBattleList(this.state); + + const allProgress: Record = {}; + const redraw = (name: string, progress: Progress) => { + allProgress[name] = progress; + bar?.render( + Object.entries(allProgress).map(([name, progress]) => ({ + completed: progress.current, + total: progress.total, + text: name, + })), + ); + }; + const stats: Record = Object.fromEntries( + exporters.map((e) => [e.name, 0]), + ); + + await Promise.all( + exporters.map((e) => + showError( + this.exportBattleList({ + fetcher, + exporter: e, + battleList, + onStep: (progress) => redraw(e.name, progress), + }) + .then((count) => { + stats[e.name] = count; + }), + ) + .catch((err) => { + console.error(`\nFailed to export to ${e.name}:`, err); + }) + ), + ); + + console.log("\nDone.", stats); + } + /** + * Export battle list. + * + * @param fetcher BattleFetcher + * @param exporter BattleExporter + * @param battleList ID list of battles, sorted by date, newest first + * @param onStep Callback function called when a battle is exported + */ + async exportBattleList( + { + fetcher, + exporter, + battleList, + onStep, + }: { + fetcher: BattleFetcher; + exporter: BattleExporter; + battleList: string[]; + onStep?: (progress: Progress) => void; + }, + ): Promise { + let exported = 0; + + onStep?.({ + current: 0, + total: 1, + }); + + const workQueue = [...await exporter.notExported(battleList)].reverse(); + + const step = async (battle: string) => { + const detail = await fetcher.fetchBattle(battle); + await exporter.exportBattle(detail); + exported += 1; + onStep?.({ + current: exported, + total: workQueue.length, + }); + }; + + if (workQueue.length > 0) { + onStep?.({ + current: exported, + total: workQueue.length, + }); + for (const battle of workQueue) { + await step(battle); + } + } + + return exported; + } +} diff --git a/cache.ts b/src/cache.ts similarity index 97% rename from cache.ts rename to src/cache.ts index f445d06..22c7f7e 100644 --- a/cache.ts +++ b/src/cache.ts @@ -1,5 +1,5 @@ // deno-lint-ignore-file require-await -import { path } from "./deps.ts"; +import { path } from "../deps.ts"; export type Cache = { read: (key: string) => Promise; diff --git a/constant.ts b/src/constant.ts similarity index 100% rename from constant.ts rename to src/constant.ts diff --git a/exporter/file.ts b/src/exporters/file.ts similarity index 97% rename from exporter/file.ts rename to src/exporters/file.ts index 1916db2..eff1b1f 100644 --- a/exporter/file.ts +++ b/src/exporters/file.ts @@ -1,5 +1,5 @@ import { BattleExporter, VsBattle } from "../types.ts"; -import { base64, path } from "../deps.ts"; +import { base64, path } from "../../deps.ts"; import { NSOAPP_VERSION, S3SI_VERSION } from "../constant.ts"; type FileExporterType = { diff --git a/exporter/stat.ink.ts b/src/exporters/stat.ink.ts similarity index 99% rename from exporter/stat.ink.ts rename to src/exporters/stat.ink.ts index b39d1fd..eae86a8 100644 --- a/exporter/stat.ink.ts +++ b/src/exporters/stat.ink.ts @@ -13,7 +13,7 @@ import { VsHistoryDetail, VsPlayer, } from "../types.ts"; -import { base64, msgpack } from "../deps.ts"; +import { base64, msgpack } from "../../deps.ts"; import { APIError } from "../APIError.ts"; import { battleId, cache } from "../utils.ts"; diff --git a/iksm.ts b/src/iksm.ts similarity index 99% rename from iksm.ts rename to src/iksm.ts index 7c6e4fc..87c6560 100644 --- a/iksm.ts +++ b/src/iksm.ts @@ -1,4 +1,4 @@ -import { CookieJar, wrapFetch } from "./deps.ts"; +import { CookieJar, wrapFetch } from "../deps.ts"; import { readline, retry, urlBase64Encode } from "./utils.ts"; import { DEFAULT_APP_USER_AGENT, diff --git a/splatnet3.ts b/src/splatnet3.ts similarity index 100% rename from splatnet3.ts rename to src/splatnet3.ts diff --git a/state.ts b/src/state.ts similarity index 100% rename from state.ts rename to src/state.ts diff --git a/types.ts b/src/types.ts similarity index 100% rename from types.ts rename to src/types.ts diff --git a/utils.ts b/src/utils.ts similarity index 97% rename from utils.ts rename to src/utils.ts index 7452eb8..c5cfdf2 100644 --- a/utils.ts +++ b/src/utils.ts @@ -1,6 +1,6 @@ import { APIError } from "./APIError.ts"; import { S3SI_NAMESPACE } from "./constant.ts"; -import { base64, io, uuid } from "./deps.ts"; +import { base64, io, uuid } from "../deps.ts"; const stdinLines = io.readLines(Deno.stdin); From 03166a3e19c5326a36cf58e8d0fdee34890b901d Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Fri, 21 Oct 2022 19:11:22 +0800 Subject: [PATCH 2/5] fix: update update-constant path --- scripts/update-constant.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/update-constant.ts b/scripts/update-constant.ts index f321f56..b9c5419 100644 --- a/scripts/update-constant.ts +++ b/scripts/update-constant.ts @@ -7,7 +7,7 @@ const ROOT_DIR = path.resolve( path.dirname(path.fromFileUrl(import.meta.url)), "..", ); -const CONSTANT_PATH = path.join(ROOT_DIR, "constant.ts"); +const CONSTANT_PATH = path.join(ROOT_DIR, "./src/constant.ts"); const STORE_URL = "https://apps.apple.com/us/app/nintendo-switch-online/id1234806557"; const SPLATNET3_URL = "https://api.lp1.av5ja.srv.nintendo.net"; From 3ddf181560468db57a80a7396114c9ce2b54167f Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Fri, 21 Oct 2022 19:37:11 +0800 Subject: [PATCH 3/5] feat: add find-id --- .gitignore | 2 +- deno.json | 19 +++++++++++++++++++ scripts/find-id.ts | 33 +++++++++++++++++++++++++++++++++ src/exporters/file.ts | 2 +- 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 deno.json create mode 100644 scripts/find-id.ts diff --git a/.gitignore b/.gitignore index ca48f09..2a025c1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.json +profile.json .vscode/ export/ cache/ diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..7086295 --- /dev/null +++ b/deno.json @@ -0,0 +1,19 @@ +{ + "tasks": { + "check": "deno check s3si.ts", + "fmt": "deno fmt", + "fmt:check": "deno fmt --check", + "lint": "deno lint", + "run": "deno run -A" + }, + "fmt": { + "files": { + "exclude": [ + "export/", + "cache/", + ".vscode/", + "profile.json" + ] + } + } +} diff --git a/scripts/find-id.ts b/scripts/find-id.ts new file mode 100644 index 0000000..3255a30 --- /dev/null +++ b/scripts/find-id.ts @@ -0,0 +1,33 @@ +import { base64 } from "../deps.ts"; +import { FileExporterType } from "../src/exporters/file.ts"; + +const dirs = Deno.args; + +const files: string[] = []; + +for (const dir of dirs) { + for await (const entry of Deno.readDir(dir)) { + if (entry.isFile) { + files.push(`${dir}/${entry.name}`); + } + } +} + +const ids = new Map(); + +for (const file of files) { + try { + const content: FileExporterType = JSON.parse(await Deno.readTextFile(file)); + const id = content.data.detail.id; + const rawId = base64.decode(id); + const uuid = new TextDecoder().decode(rawId.slice(rawId.length - 36)); + if (ids.has(uuid)) { + console.log( + `Duplicate: ${uuid}:${id} in ${file} and ${uuid}:${ids.get(uuid)}`, + ); + } + ids.set(uuid, id); + } catch (e) { + console.log("Failed to process file", file, e); + } +} diff --git a/src/exporters/file.ts b/src/exporters/file.ts index eff1b1f..c6f96d9 100644 --- a/src/exporters/file.ts +++ b/src/exporters/file.ts @@ -2,7 +2,7 @@ import { BattleExporter, VsBattle } from "../types.ts"; import { base64, path } from "../../deps.ts"; import { NSOAPP_VERSION, S3SI_VERSION } from "../constant.ts"; -type FileExporterType = { +export type FileExporterType = { type: "VS" | "COOP"; nsoVersion: string; s3siVersion: string; From 6d5e614879bb4a52248dd0bfb5c9b274cfb30cb5 Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Fri, 21 Oct 2022 19:44:28 +0800 Subject: [PATCH 4/5] style: remove unused default value --- s3si.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/s3si.ts b/s3si.ts index 97ca267..5a79401 100644 --- a/s3si.ts +++ b/s3si.ts @@ -12,9 +12,6 @@ const parseArgs = (args: string[]) => { "exporter": ["e"], "noProgress": ["n", "no-progress"], }, - default: { - progress: true, - }, }); return parsed; }; From c6acded86aac09f1721ba4a3353076a09725662b Mon Sep 17 00:00:00 2001 From: spacemeowx2 Date: Fri, 21 Oct 2022 19:45:15 +0800 Subject: [PATCH 5/5] build: bump version --- src/constant.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constant.ts b/src/constant.ts index 90ab5c3..b7194ae 100644 --- a/src/constant.ts +++ b/src/constant.ts @@ -1,7 +1,7 @@ import type { StatInkPostBody, VsHistoryDetail } from "./types.ts"; export const AGENT_NAME = "s3si.ts"; -export const S3SI_VERSION = "0.1.2"; +export const S3SI_VERSION = "0.1.3"; export const NSOAPP_VERSION = "2.3.1"; export const WEB_VIEW_VERSION = "1.0.0-216d0219";