fix(plugins/community/splatoon): upgrade s3si version
This commit is contained in:
1 parent
1a95c68e69
commit
cea9e4307e
2 files changed
+280
-90
No files matched your search
@@ -216,7 +216,7 @@ export default async function({login, q, imports, data, account}, {enabled = fal
|
||||
icon: await imports.imgb64(assets.stages[data.detail.coopStage.name]),
|
||||
},
|
||||
date: data.detail.playedTime,
|
||||
grade: data.detail.afterGrade.name,
|
||||
grade: data.detail.afterGrade?.name ?? "",
|
||||
})),
|
||||
),
|
||||
}
|
||||
|
||||
@@ -12,9 +12,26 @@ class APIError extends Error {
|
||||
}
|
||||
}
|
||||
const AGENT_NAME = "s3si.ts";
|
||||
const S3SI_VERSION = "0.3.1";
|
||||
const NSOAPP_VERSION = "2.5.0";
|
||||
const WEB_VIEW_VERSION = "3.0.0-2857bc50";
|
||||
const S3SI_VERSION = "0.4.5";
|
||||
const NSOAPP_VERSION = "2.6.0";
|
||||
const WEB_VIEW_VERSION = "4.0.0-d5178440";
|
||||
var Queries;
|
||||
(function(Queries) {
|
||||
Queries["HomeQuery"] = "7dcc64ea27a08e70919893a0d3f70871";
|
||||
Queries["LatestBattleHistoriesQuery"] = "0d90c7576f1916469b2ae69f64292c02";
|
||||
Queries["RegularBattleHistoriesQuery"] = "3baef04b095ad8975ea679d722bc17de";
|
||||
Queries["BankaraBattleHistoriesQuery"] = "0438ea6978ae8bd77c5d1250f4f84803";
|
||||
Queries["XBattleHistoriesQuery"] = "6796e3cd5dc3ebd51864dc709d899fc5";
|
||||
Queries["EventBattleHistoriesQuery"] = "9744fcf676441873c7c8a51285b6aa4d";
|
||||
Queries["PrivateBattleHistoriesQuery"] = "8e5ae78b194264a6c230e262d069bd28";
|
||||
Queries["VsHistoryDetailQuery"] = "9ee0099fbe3d8db2a838a75cf42856dd";
|
||||
Queries["CoopHistoryQuery"] = "91b917becd2fa415890f5b47e15ffb15";
|
||||
Queries["CoopHistoryDetailQuery"] = "379f0d9b78b531be53044bcac031b34b";
|
||||
Queries["myOutfitCommonDataFilteringConditionQuery"] = "d02ab22c9dccc440076055c8baa0fa7a";
|
||||
Queries["myOutfitCommonDataEquipmentsQuery"] = "d29cd0c2b5e6bac90dd5b817914832f8";
|
||||
Queries["HistoryRecordQuery"] = "d9246baf077b2a29b5f7aac321810a77";
|
||||
Queries["ConfigureAnalyticsQuery"] = "f8ae00773cc412a50dd41a6d9a159ddd";
|
||||
})(Queries || (Queries = {}));
|
||||
const S3SI_LINK = "https://github.com/spacemeowx2/s3si.ts";
|
||||
const USERAGENT = `${AGENT_NAME}/${S3SI_VERSION} (${S3SI_LINK})`;
|
||||
const DEFAULT_APP_USER_AGENT = "Mozilla/5.0 (Linux; Android 11; Pixel 5) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/94.0.4606.61 Mobile Safari/537.36";
|
||||
@@ -1243,13 +1260,13 @@ const MIN_BUF_SIZE = 16;
|
||||
const CR = "\r".charCodeAt(0);
|
||||
const LF = "\n".charCodeAt(0);
|
||||
class BufferFullError extends Error {
|
||||
partial;
|
||||
name;
|
||||
constructor(partial){
|
||||
super("Buffer full");
|
||||
this.partial = partial;
|
||||
this.name = "BufferFullError";
|
||||
}
|
||||
partial;
|
||||
}
|
||||
class PartialReadError extends Error {
|
||||
name = "PartialReadError";
|
||||
@@ -1753,6 +1770,8 @@ class MultiReader {
|
||||
}
|
||||
}
|
||||
class LimitedReader {
|
||||
reader;
|
||||
limit;
|
||||
constructor(reader, limit){
|
||||
this.reader = reader;
|
||||
this.limit = limit;
|
||||
@@ -1771,8 +1790,6 @@ class LimitedReader {
|
||||
this.limit -= n;
|
||||
return n;
|
||||
}
|
||||
reader;
|
||||
limit;
|
||||
}
|
||||
const DEFAULT_BUFFER_SIZE = 32 * 1024;
|
||||
async function copyN(r, dest, size) {
|
||||
@@ -1836,6 +1853,7 @@ function sliceLongToBytes(d, dest = Array.from({
|
||||
}
|
||||
const decoder = new TextDecoder();
|
||||
class StringWriter {
|
||||
base;
|
||||
#chunks;
|
||||
#byteLength;
|
||||
#cache;
|
||||
@@ -1869,7 +1887,6 @@ class StringWriter {
|
||||
this.#cache = decoder.decode(buf);
|
||||
return this.#cache;
|
||||
}
|
||||
base;
|
||||
}
|
||||
const mod2 = {
|
||||
copyN: copyN,
|
||||
@@ -2144,12 +2161,12 @@ function utf8DecodeTD(bytes, inputOffset, byteLength) {
|
||||
return sharedTextDecoder.decode(stringBytes);
|
||||
}
|
||||
class ExtData {
|
||||
type;
|
||||
data;
|
||||
constructor(type, data){
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
type;
|
||||
data;
|
||||
}
|
||||
function setUint64(view, offset, value) {
|
||||
const high = value / 0x1_0000_0000;
|
||||
@@ -2336,6 +2353,13 @@ function createDataView(buffer) {
|
||||
return new DataView(bufferView.buffer, bufferView.byteOffset, bufferView.byteLength);
|
||||
}
|
||||
class Encoder {
|
||||
extensionCodec;
|
||||
context;
|
||||
maxDepth;
|
||||
initialBufferSize;
|
||||
sortKeys;
|
||||
forceFloat32;
|
||||
ignoreUndefined;
|
||||
pos;
|
||||
view;
|
||||
bytes;
|
||||
@@ -2645,13 +2669,6 @@ class Encoder {
|
||||
setInt64(this.view, this.pos, value);
|
||||
this.pos += 8;
|
||||
}
|
||||
extensionCodec;
|
||||
context;
|
||||
maxDepth;
|
||||
initialBufferSize;
|
||||
sortKeys;
|
||||
forceFloat32;
|
||||
ignoreUndefined;
|
||||
}
|
||||
const defaultEncodeOptions = {};
|
||||
function encode1(value, options = defaultEncodeOptions) {
|
||||
@@ -2662,6 +2679,8 @@ function prettyByte(__byte) {
|
||||
return `${__byte < 0 ? "-" : ""}0x${Math.abs(__byte).toString(16).padStart(2, "0")}`;
|
||||
}
|
||||
class CachedKeyDecoder {
|
||||
maxKeyLength;
|
||||
maxLengthPerKey;
|
||||
hit;
|
||||
miss;
|
||||
caches;
|
||||
@@ -2717,8 +2736,6 @@ class CachedKeyDecoder {
|
||||
this.store(slicedCopyOfBytes, value);
|
||||
return value;
|
||||
}
|
||||
maxKeyLength;
|
||||
maxLengthPerKey;
|
||||
}
|
||||
var State;
|
||||
(function(State) {
|
||||
@@ -2744,6 +2761,14 @@ const DataViewIndexOutOfBoundsError = (()=>{
|
||||
const MORE_DATA = new DataViewIndexOutOfBoundsError("Insufficient data");
|
||||
const sharedCachedKeyDecoder = new CachedKeyDecoder();
|
||||
class Decoder {
|
||||
extensionCodec;
|
||||
context;
|
||||
maxStrLength;
|
||||
maxBinLength;
|
||||
maxArrayLength;
|
||||
maxMapLength;
|
||||
maxExtLength;
|
||||
keyDecoder;
|
||||
totalPos;
|
||||
pos;
|
||||
view;
|
||||
@@ -3191,14 +3216,6 @@ class Decoder {
|
||||
this.pos += 8;
|
||||
return value;
|
||||
}
|
||||
extensionCodec;
|
||||
context;
|
||||
maxStrLength;
|
||||
maxBinLength;
|
||||
maxArrayLength;
|
||||
maxMapLength;
|
||||
maxExtLength;
|
||||
keyDecoder;
|
||||
}
|
||||
const defaultDecodeOptions = {};
|
||||
function decode1(buffer, options = defaultDecodeOptions) {
|
||||
@@ -4449,7 +4466,7 @@ function globToRegExp(glob, { extended =true , globstar: globstarOption = true ,
|
||||
else if (value == "lower") segment += "a-z";
|
||||
else if (value == "print") segment += "\x20-\x7E";
|
||||
else if (value == "punct") {
|
||||
segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_ÔÇÿ{|}~";
|
||||
segment += "!\"#$%&'()*+,\\-./:;<=>?@[\\\\\\]^_‘{|}~";
|
||||
} else if (value == "space") segment += "\\s\v";
|
||||
else if (value == "upper") segment += "A-Z";
|
||||
else if (value == "word") segment += "\\w";
|
||||
@@ -5072,6 +5089,11 @@ function urlSimplify(url) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
const battleTime = (id)=>{
|
||||
const { timestamp } = parseHistoryDetailId(id);
|
||||
const dateStr = timestamp.replace(/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/, "$1-$2-$3T$4:$5:$6Z");
|
||||
return new Date(dateStr);
|
||||
};
|
||||
async function loginSteps({ newFetcher }, step2) {
|
||||
const fetch = newFetcher();
|
||||
if (!step2) {
|
||||
@@ -5182,12 +5204,13 @@ async function getGToken({ fApi , sessionToken , env }) {
|
||||
}
|
||||
});
|
||||
const uiRespJson = await uiResp.json();
|
||||
const { nickname , birthday , language , country } = uiRespJson;
|
||||
const { nickname , birthday , language , country , id: userId } = uiRespJson;
|
||||
const getIdToken2 = async (idToken)=>{
|
||||
const { f , request_id: requestId , timestamp } = await callImink({
|
||||
fApi,
|
||||
step: 1,
|
||||
idToken,
|
||||
userId,
|
||||
env
|
||||
});
|
||||
const resp = await fetch.post({
|
||||
@@ -5214,20 +5237,26 @@ async function getGToken({ fApi , sessionToken , env }) {
|
||||
});
|
||||
const respJson = await resp.json();
|
||||
const idToken2 = respJson?.result?.webApiServerCredential?.accessToken;
|
||||
if (!idToken2) {
|
||||
const coralUserId = respJson?.result?.user?.id?.toString();
|
||||
if (!idToken2 || !coralUserId) {
|
||||
throw new APIError({
|
||||
response: resp,
|
||||
json: respJson,
|
||||
message: "No idToken2 found"
|
||||
message: `No idToken2 or coralUserId found. Please try again later. (${idToken2.length}, ${coralUserId.length})`
|
||||
});
|
||||
}
|
||||
return idToken2;
|
||||
return [
|
||||
idToken2,
|
||||
coralUserId
|
||||
];
|
||||
};
|
||||
const getGToken = async (idToken)=>{
|
||||
const getGToken = async (idToken, coralUserId)=>{
|
||||
const { f , request_id: requestId , timestamp } = await callImink({
|
||||
step: 2,
|
||||
idToken,
|
||||
fApi,
|
||||
userId,
|
||||
coralUserId,
|
||||
env
|
||||
});
|
||||
const resp = await fetch.post({
|
||||
@@ -5261,8 +5290,8 @@ async function getGToken({ fApi , sessionToken , env }) {
|
||||
}
|
||||
return webServiceToken;
|
||||
};
|
||||
const idToken2 = await retry(()=>getIdToken2(idToken));
|
||||
const webServiceToken = await retry(()=>getGToken(idToken2));
|
||||
const [idToken2, coralUserId] = await retry(()=>getIdToken2(idToken));
|
||||
const webServiceToken = await retry(()=>getGToken(idToken2, coralUserId));
|
||||
return {
|
||||
webServiceToken,
|
||||
nickname,
|
||||
@@ -5359,7 +5388,8 @@ async function getSessionToken({ fetch , sessionTokenCode , authCodeVerifier })
|
||||
}
|
||||
return json["session_token"];
|
||||
}
|
||||
async function callImink({ fApi , step , idToken , env }) {
|
||||
async function callImink(params) {
|
||||
const { fApi , step , idToken , userId , coralUserId , env } = params;
|
||||
const { post } = env.newFetcher();
|
||||
const resp = await post({
|
||||
url: fApi,
|
||||
@@ -5369,7 +5399,9 @@ async function callImink({ fApi , step , idToken , env }) {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"token": idToken,
|
||||
"hash_method": step
|
||||
"hash_method": step,
|
||||
"na_id": userId,
|
||||
"coral_user_id": coralUserId
|
||||
})
|
||||
});
|
||||
return await resp.json();
|
||||
@@ -5422,6 +5454,7 @@ const DEFAULT_STATE = {
|
||||
monitorInterval: 500
|
||||
};
|
||||
class FileStateBackend {
|
||||
path;
|
||||
constructor(path){
|
||||
this.path = path;
|
||||
}
|
||||
@@ -5436,7 +5469,6 @@ class FileStateBackend {
|
||||
await Deno.writeTextFile(swapPath, data);
|
||||
await Deno.rename(swapPath, this.path);
|
||||
}
|
||||
path;
|
||||
}
|
||||
class Profile {
|
||||
_state;
|
||||
@@ -5469,29 +5501,15 @@ class Profile {
|
||||
}
|
||||
}
|
||||
}
|
||||
var Queries;
|
||||
(function(Queries) {
|
||||
Queries["HomeQuery"] = "22e2fa8294168003c21b00c333c35384";
|
||||
Queries["LatestBattleHistoriesQuery"] = "4f5f26e64bca394b45345a65a2f383bd";
|
||||
Queries["RegularBattleHistoriesQuery"] = "d5b795d09e67ce153e622a184b7e7dfa";
|
||||
Queries["BankaraBattleHistoriesQuery"] = "de4754588109b77dbcb90fbe44b612ee";
|
||||
Queries["XBattleHistoriesQuery"] = "45c74fefb45a49073207229ca65f0a62";
|
||||
Queries["PrivateBattleHistoriesQuery"] = "1d6ed57dc8b801863126ad4f351dfb9a";
|
||||
Queries["VsHistoryDetailQuery"] = "291295ad311b99a6288fc95a5c4cb2d2";
|
||||
Queries["CoopHistoryQuery"] = "6ed02537e4a65bbb5e7f4f23092f6154";
|
||||
Queries["CoopHistoryDetailQuery"] = "379f0d9b78b531be53044bcac031b34b";
|
||||
Queries["myOutfitCommonDataFilteringConditionQuery"] = "d02ab22c9dccc440076055c8baa0fa7a";
|
||||
Queries["myOutfitCommonDataEquipmentsQuery"] = "d29cd0c2b5e6bac90dd5b817914832f8";
|
||||
Queries["HistoryRecordQuery"] = "32b6771f94083d8f04848109b7300af5";
|
||||
Queries["ConfigureAnalyticsQuery"] = "f8ae00773cc412a50dd41a6d9a159ddd";
|
||||
})(Queries || (Queries = {}));
|
||||
var BattleListType;
|
||||
(function(BattleListType) {
|
||||
BattleListType[BattleListType["Latest"] = 0] = "Latest";
|
||||
BattleListType[BattleListType["Regular"] = 1] = "Regular";
|
||||
BattleListType[BattleListType["Bankara"] = 2] = "Bankara";
|
||||
BattleListType[BattleListType["Private"] = 3] = "Private";
|
||||
BattleListType[BattleListType["Coop"] = 4] = "Coop";
|
||||
BattleListType[BattleListType["Event"] = 3] = "Event";
|
||||
BattleListType[BattleListType["XBattle"] = 4] = "XBattle";
|
||||
BattleListType[BattleListType["Private"] = 5] = "Private";
|
||||
BattleListType[BattleListType["Coop"] = 6] = "Coop";
|
||||
})(BattleListType || (BattleListType = {}));
|
||||
var SummaryEnum;
|
||||
(function(SummaryEnum) {
|
||||
@@ -5596,6 +5614,8 @@ class Splatnet3 {
|
||||
[BattleListType.Latest]: ()=>this.request(Queries.LatestBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.latestBattleHistories)),
|
||||
[BattleListType.Regular]: ()=>this.request(Queries.RegularBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.regularBattleHistories)),
|
||||
[BattleListType.Bankara]: ()=>this.request(Queries.BankaraBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.bankaraBattleHistories)),
|
||||
[BattleListType.XBattle]: ()=>this.request(Queries.XBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.xBattleHistories)),
|
||||
[BattleListType.Event]: ()=>this.request(Queries.EventBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.eventBattleHistories)),
|
||||
[BattleListType.Private]: ()=>this.request(Queries.PrivateBattleHistoriesQuery).then((r)=>getIdsFromGroups(r.privateBattleHistories)),
|
||||
[BattleListType.Coop]: ()=>this.request(Queries.CoopHistoryQuery).then((r)=>getIdsFromGroups(r.coopResult))
|
||||
};
|
||||
@@ -5614,6 +5634,24 @@ class Splatnet3 {
|
||||
async getBattleList(battleListType = BattleListType.Latest) {
|
||||
return await this.BATTLE_LIST_TYPE_MAP[battleListType]();
|
||||
}
|
||||
async getAllBattleList() {
|
||||
const ALL_TYPE = [
|
||||
BattleListType.Regular,
|
||||
BattleListType.Bankara,
|
||||
BattleListType.XBattle,
|
||||
BattleListType.Event,
|
||||
BattleListType.Private
|
||||
];
|
||||
const ids = [];
|
||||
for (const type of ALL_TYPE){
|
||||
ids.push(...await this.getBattleList(type));
|
||||
}
|
||||
const timeMap = new Map(ids.map((id)=>[
|
||||
id,
|
||||
battleTime(id)
|
||||
]));
|
||||
return ids.sort((a, b)=>timeMap.get(b).getTime() - timeMap.get(a).getTime());
|
||||
}
|
||||
getBattleDetail(id) {
|
||||
return this.request(Queries.VsHistoryDetailQuery, {
|
||||
vsResultId: id
|
||||
@@ -5689,6 +5727,7 @@ class MemoryCache {
|
||||
}
|
||||
}
|
||||
class FileCache {
|
||||
path;
|
||||
constructor(path){
|
||||
this.path = path;
|
||||
}
|
||||
@@ -5720,8 +5759,8 @@ class FileCache {
|
||||
await Deno.writeFile(swapPath, data);
|
||||
await Deno.rename(swapPath, path);
|
||||
}
|
||||
path;
|
||||
}
|
||||
const __default = JSON.parse("[\n {\n \"key\": \"ink_saver_main\",\n \"name\": {\n \"de-DE\": \"Hauptverbrauch\",\n \"en-GB\": \"Ink Saver (Main)\",\n \"en-US\": \"Ink Saver (Main)\",\n \"es-ES\": \"Tintahorro (ppal.)\",\n \"es-MX\": \"Ahorro tinta (ppal.)\",\n \"fr-CA\": \"Encrémenteur (pr.)\",\n \"fr-FR\": \"Encrémenteur (pr.)\",\n \"it-IT\": \"Eco-colore princ.\",\n \"ja-JP\": \"インク効率アップ(メイン)\",\n \"ko-KR\": \"잉크 효율 업(메인)\",\n \"nl-NL\": \"Hoofdspaarder\",\n \"ru-RU\": \"Основной баллон X\",\n \"zh-CN\": \"提升墨汁效率(主要武器)\",\n \"zh-TW\": \"提升墨汁效率(主要武器)\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"ink_saver_sub\",\n \"name\": {\n \"de-DE\": \"Sekundärverbrauch\",\n \"en-GB\": \"Ink Saver (Sub)\",\n \"en-US\": \"Ink Saver (Sub)\",\n \"es-ES\": \"Tintahorro (sec.)\",\n \"es-MX\": \"Ahorro tinta (sec.)\",\n \"fr-CA\": \"Encrémenteur (sec.)\",\n \"fr-FR\": \"Encrémenteur (sec.)\",\n \"it-IT\": \"Eco-colore second.\",\n \"ja-JP\": \"インク効率アップ(サブ)\",\n \"ko-KR\": \"잉크 효율 업(서브)\",\n \"nl-NL\": \"Subspaarder\",\n \"ru-RU\": \"Запасной баллон X\",\n \"zh-CN\": \"提升墨汁效率(次要武器)\",\n \"zh-TW\": \"提升墨汁效率(次要武器)\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"ink_recovery_up\",\n \"name\": {\n \"de-DE\": \"Regeneration +\",\n \"en-GB\": \"Ink Recovery Up\",\n \"en-US\": \"Ink Recovery Up\",\n \"es-ES\": \"Recarga rápida\",\n \"es-MX\": \"Mejor recarga tinta\",\n \"fr-CA\": \"Levée d'encre\",\n \"fr-FR\": \"Levée d'encre\",\n \"it-IT\": \"Recupero colore +\",\n \"ja-JP\": \"インク回復力アップ\",\n \"ko-KR\": \"잉크 회복력 업\",\n \"nl-NL\": \"Inktvulling\",\n \"ru-RU\": \"Быстрый баллон\",\n \"zh-CN\": \"提升墨汁回复力\",\n \"zh-TW\": \"提升墨汁回復力\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"run_speed_up\",\n \"name\": {\n \"de-DE\": \"Lauftempo +\",\n \"en-GB\": \"Run Speed Up\",\n \"en-US\": \"Run Speed Up\",\n \"es-ES\": \"Supercarrera\",\n \"es-MX\": \"Carrera acelerada\",\n \"fr-CA\": \"Course à pied\",\n \"fr-FR\": \"Course à pied\",\n \"it-IT\": \"Velocità +\",\n \"ja-JP\": \"ヒト移動速度アップ\",\n \"ko-KR\": \"인간 이동 속도 업\",\n \"nl-NL\": \"Hardloper\",\n \"ru-RU\": \"Спринтер\",\n \"zh-CN\": \"提升人类移动速度\",\n \"zh-TW\": \"提升人類移動速度\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"swim_speed_up\",\n \"name\": {\n \"de-DE\": \"Schwimmtempo +\",\n \"en-GB\": \"Swim Speed Up\",\n \"en-US\": \"Swim Speed Up\",\n \"es-ES\": \"Superbuceo\",\n \"es-MX\": \"Nado acelerado\",\n \"fr-CA\": \"Turbo-calmar\",\n \"fr-FR\": \"Turbo-calamar\",\n \"it-IT\": \"Velocità nuoto +\",\n \"ja-JP\": \"イカダッシュ速度アップ\",\n \"ko-KR\": \"징어대시 속도 업\",\n \"nl-NL\": \"Zwemdiploma\",\n \"ru-RU\": \"Плавунец\",\n \"zh-CN\": \"提升鱿鱼冲刺速度\",\n \"zh-TW\": \"提升魷魚衝刺速度\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"special_charge_up\",\n \"name\": {\n \"de-DE\": \"Spezialladezeit +\",\n \"en-GB\": \"Special Charge Up\",\n \"en-US\": \"Special Charge Up\",\n \"es-ES\": \"Recarga especial\",\n \"es-MX\": \"Recarga especial\",\n \"fr-CA\": \"Jauge spéciale +\",\n \"fr-FR\": \"Jauge spéciale +\",\n \"it-IT\": \"Ricarica speciale +\",\n \"ja-JP\": \"スペシャル増加量アップ\",\n \"ko-KR\": \"스페셜 증가량 업\",\n \"nl-NL\": \"Speciaallader\",\n \"ru-RU\": \"Особый насос\",\n \"zh-CN\": \"提升特殊武器增加量\",\n \"zh-TW\": \"提升特殊武器增加量\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"special_saver\",\n \"name\": {\n \"de-DE\": \"Spezialabzug -\",\n \"en-GB\": \"Special Saver\",\n \"en-US\": \"Special Saver\",\n \"es-ES\": \"Reducción especial\",\n \"es-MX\": \"Ahorro especial\",\n \"fr-CA\": \"Baisse spéciale -\",\n \"fr-FR\": \"Baisse spéciale -\",\n \"it-IT\": \"Riduzione speciale -\",\n \"ja-JP\": \"スペシャル減少量ダウン\",\n \"ko-KR\": \"스페셜 감소량 다운\",\n \"nl-NL\": \"Speciaalspaarder\",\n \"ru-RU\": \"Особый резерв\",\n \"zh-CN\": \"降低特殊武器减少量\",\n \"zh-TW\": \"降低特殊武器減少量\"\n },\n \"primary_only\": false\n },\n {\n \"key\": \"sLine truncated
|
||||
const COOP_POINT_MAP = {
|
||||
0: -20,
|
||||
1: -10,
|
||||
@@ -5739,6 +5778,8 @@ async function checkResponse(resp) {
|
||||
}
|
||||
}
|
||||
class StatInkAPI {
|
||||
statInkApiKey;
|
||||
env;
|
||||
statInk;
|
||||
FETCH_LOCK;
|
||||
cache;
|
||||
@@ -5751,7 +5792,7 @@ class StatInkAPI {
|
||||
this._salmonWeaponMap = new Map();
|
||||
this.getSalmonWeapon = ()=>this._getCached(`${this.statInk}/api/v3/salmon/weapon?full=1`);
|
||||
this.getWeapon = ()=>this._getCached(`${this.statInk}/api/v3/weapon?full=1`);
|
||||
this.getAbility = ()=>this._getCached(`${this.statInk}/api/v3/ability?full=1`);
|
||||
this.getAbility = ()=>__default;
|
||||
this.getStage = ()=>this._getCached(`${this.statInk}/api/v3/stage`);
|
||||
if (statInkApiKey.length !== 43) {
|
||||
throw new Error("Invalid stat.ink API key");
|
||||
@@ -5854,8 +5895,8 @@ class StatInkAPI {
|
||||
}
|
||||
}
|
||||
_getAliasName(name) {
|
||||
const STAT_INK_DOT = "┬À";
|
||||
const SPLATNET_DOT = "";
|
||||
const STAT_INK_DOT = "·";
|
||||
const SPLATNET_DOT = "‧";
|
||||
if (name.includes(STAT_INK_DOT)) {
|
||||
return [
|
||||
name,
|
||||
@@ -5890,8 +5931,6 @@ class StatInkAPI {
|
||||
getWeapon;
|
||||
getAbility;
|
||||
getStage;
|
||||
statInkApiKey;
|
||||
env;
|
||||
}
|
||||
class StatInkExporter {
|
||||
name = "stat.ink";
|
||||
@@ -5964,6 +6003,8 @@ class StatInkExporter {
|
||||
}
|
||||
} else if (vsMode === "X_MATCH") {
|
||||
return "xmatch";
|
||||
} else if (vsMode === "LEAGUE") {
|
||||
return "event";
|
||||
}
|
||||
throw new TypeError(`Unknown vsMode ${vsMode}`);
|
||||
}
|
||||
@@ -6028,7 +6069,7 @@ class StatInkExporter {
|
||||
return result;
|
||||
};
|
||||
async mapBattle({ groupInfo , challengeProgress , bankaraMatchChallenge , listNode , detail: vsDetail , rankBeforeState , rankState }) {
|
||||
const { knockout , vsRule: { rule } , myTeam , otherTeams , bankaraMatch , festMatch , playedTime } = vsDetail;
|
||||
const { knockout , vsRule: { rule } , myTeam , otherTeams , bankaraMatch , leagueMatch , festMatch , playedTime } = vsDetail;
|
||||
const self = vsDetail.myTeam.players.find((i)=>i.isMyself);
|
||||
if (!self) {
|
||||
throw new Error("Self not found");
|
||||
@@ -6124,6 +6165,10 @@ class StatInkExporter {
|
||||
result.rank_after_s_plus = result.rank_before_s_plus;
|
||||
}
|
||||
}
|
||||
if (leagueMatch) {
|
||||
result.event = leagueMatch.leagueMatchEvent?.id;
|
||||
result.event_power = leagueMatch.myLeaguePower;
|
||||
}
|
||||
if (challengeProgress) {
|
||||
result.challenge_win = challengeProgress.winCount;
|
||||
result.challenge_lose = challengeProgress.loseCount;
|
||||
@@ -6134,6 +6179,7 @@ class StatInkExporter {
|
||||
result.x_power_after = groupInfo.xMatchMeasurement.xPowerAfter;
|
||||
}
|
||||
}
|
||||
result.bankara_power_after = vsDetail.bankaraMatch?.bankaraPower?.power;
|
||||
if (rankBeforeState && rankState) {
|
||||
result.rank_before_exp = rankBeforeState.rankPoint;
|
||||
result.rank_after_exp = rankState.rankPoint;
|
||||
@@ -6237,7 +6283,8 @@ class StatInkExporter {
|
||||
golden_quota: wave.deliverNorm,
|
||||
golden_appearances: wave.goldenPopCount,
|
||||
golden_delivered: wave.teamDeliverCount,
|
||||
special_uses
|
||||
special_uses,
|
||||
danger_rate: null
|
||||
};
|
||||
}
|
||||
async mapCoop({ gradeBefore , groupInfo , detail }) {
|
||||
@@ -6255,9 +6302,10 @@ class StatInkExporter {
|
||||
]));
|
||||
const title_after = detail.afterGrade ? b64Number(detail.afterGrade.id).toString() : undefined;
|
||||
const title_exp_after = detail.afterGradePoint;
|
||||
const maxWaves = detail.rule === "TEAM_CONTEST" ? 5 : 3;
|
||||
let clear_waves;
|
||||
if (waveResults.length > 0) {
|
||||
clear_waves = waveResults.filter((i)=>i.waveNumber < 4).length - 1 + (resultWave === 0 ? 1 : 0);
|
||||
clear_waves = waveResults.filter((i)=>i.waveNumber < maxWaves + 1).length - 1 + (resultWave === 0 ? 1 : 0);
|
||||
} else {
|
||||
clear_waves = 0;
|
||||
}
|
||||
@@ -6282,7 +6330,7 @@ class StatInkExporter {
|
||||
}
|
||||
}
|
||||
let fail_reason = null;
|
||||
if (clear_waves !== 3 && waveResults.length > 0) {
|
||||
if (clear_waves !== maxWaves && waveResults.length > 0) {
|
||||
const lastWave = waveResults[waveResults.length - 1];
|
||||
if (lastWave.teamDeliverCount >= lastWave.deliverNorm) {
|
||||
fail_reason = "wipe_out";
|
||||
@@ -6292,8 +6340,9 @@ class StatInkExporter {
|
||||
uuid: await gameId(detail.id),
|
||||
private: groupInfo?.mode === "PRIVATE_CUSTOM" ? "yes" : "no",
|
||||
big_run: detail.rule === "BIG_RUN" ? "yes" : "no",
|
||||
eggstra_work: detail.rule === "TEAM_CONTEST" ? "yes" : "no",
|
||||
stage: b64Number(detail.coopStage.id).toString(),
|
||||
danger_rate: dangerRate * 100,
|
||||
danger_rate: detail.rule === "TEAM_CONTEST" ? null : dangerRate * 100,
|
||||
clear_waves,
|
||||
fail_reason,
|
||||
king_smell: smellMeter,
|
||||
@@ -6326,6 +6375,53 @@ class StatInkExporter {
|
||||
automated: "yes",
|
||||
start_at: startedAt
|
||||
};
|
||||
if (detail.rule === "TEAM_CONTEST") {
|
||||
let lastWave;
|
||||
for (const [wave] of result.waves.map((p, i)=>[
|
||||
p,
|
||||
i
|
||||
])){
|
||||
let haz_level;
|
||||
if (!lastWave) {
|
||||
haz_level = 60;
|
||||
} else {
|
||||
const num_players = result.players.length;
|
||||
const quota = lastWave.golden_quota;
|
||||
const delivered = lastWave.golden_delivered;
|
||||
let added_percent = 0;
|
||||
if (num_players == 4) {
|
||||
if (delivered >= quota * 2) {
|
||||
added_percent = 60;
|
||||
} else if (delivered >= quota * 1.5) {
|
||||
added_percent = 30;
|
||||
}
|
||||
} else if (num_players == 3) {
|
||||
if (delivered >= quota * 2) {
|
||||
added_percent = 40;
|
||||
} else if (delivered >= quota * 1.5) {
|
||||
added_percent = 20;
|
||||
}
|
||||
} else if (num_players == 2) {
|
||||
if (delivered >= quota * 2) {
|
||||
added_percent = 20;
|
||||
} else if (delivered >= quota * 1.5) {
|
||||
added_percent = 10;
|
||||
added_percent = 5;
|
||||
}
|
||||
} else if (num_players == 1) {
|
||||
if (delivered >= quota * 2) {
|
||||
added_percent = 10;
|
||||
} else if (delivered >= quota * 1.5) {
|
||||
added_percent = 5;
|
||||
}
|
||||
}
|
||||
const prev_percent = lastWave.danger_rate;
|
||||
haz_level = prev_percent + added_percent;
|
||||
}
|
||||
wave.danger_rate = haz_level;
|
||||
lastWave = wave;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -6347,6 +6443,7 @@ function replacer(key, value) {
|
||||
return typeof value === "string" ? urlSimplify(value) : undefined;
|
||||
}
|
||||
class FileExporter {
|
||||
exportPath;
|
||||
name;
|
||||
constructor(exportPath){
|
||||
this.exportPath = exportPath;
|
||||
@@ -6455,7 +6552,6 @@ class FileExporter {
|
||||
}
|
||||
return out;
|
||||
}
|
||||
exportPath;
|
||||
}
|
||||
const SEASONS = [
|
||||
{
|
||||
@@ -6475,6 +6571,12 @@ const SEASONS = [
|
||||
name: "Fresh Season 2023",
|
||||
start: new Date("2023-03-01T00:00:00+00:00"),
|
||||
end: new Date("2023-06-01T00:00:00+00:00")
|
||||
},
|
||||
{
|
||||
id: "season202306",
|
||||
name: "Sizzle Season 2023",
|
||||
start: new Date("2023-06-01T00:00:00+00:00"),
|
||||
end: new Date("2023-09-01T00:00:00+00:00")
|
||||
}
|
||||
];
|
||||
const getSeason = (date)=>{
|
||||
@@ -6665,11 +6767,6 @@ function addRank(state, delta) {
|
||||
}
|
||||
};
|
||||
}
|
||||
const battleTime = (id)=>{
|
||||
const { timestamp } = parseHistoryDetailId(id);
|
||||
const dateStr = timestamp.replace(/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/, "$1-$2-$3T$4:$5:$6Z");
|
||||
return new Date(dateStr);
|
||||
};
|
||||
function beginPoint(state, flatten) {
|
||||
if (state) {
|
||||
const index = flatten.findIndex((i)=>i.gameId === state.gameId);
|
||||
@@ -6767,6 +6864,7 @@ function getRankStateByDelta(i) {
|
||||
};
|
||||
}
|
||||
class RankTracker {
|
||||
state;
|
||||
deltaMap;
|
||||
stateMap;
|
||||
constructor(state){
|
||||
@@ -6782,6 +6880,9 @@ class RankTracker {
|
||||
this.state = state;
|
||||
}
|
||||
async updateState(history) {
|
||||
if (history.length === 0) {
|
||||
return;
|
||||
}
|
||||
const flatten = await Promise.all(history.flatMap(({ historyDetails , bankaraMatchChallenge })=>{
|
||||
return historyDetails.nodes.map((j, index)=>({
|
||||
id: j.id,
|
||||
@@ -6811,7 +6912,6 @@ class RankTracker {
|
||||
}
|
||||
return curState;
|
||||
}
|
||||
state;
|
||||
}
|
||||
class GameFetcher {
|
||||
_splatnet;
|
||||
@@ -7018,6 +7118,7 @@ const DEFAULT_OPTS = {
|
||||
noProgress: false,
|
||||
monitor: false,
|
||||
withSummary: false,
|
||||
listMethod: "auto",
|
||||
env: DEFAULT_ENV
|
||||
};
|
||||
class StepProgress {
|
||||
@@ -7033,6 +7134,89 @@ class StepProgress {
|
||||
this.skipped = {};
|
||||
}
|
||||
}
|
||||
class BattleListFetcher {
|
||||
splatnet;
|
||||
listMethod;
|
||||
allBattleList;
|
||||
latestBattleList;
|
||||
allLock;
|
||||
latestLock;
|
||||
constructor(listMethod, splatnet){
|
||||
this.splatnet = splatnet;
|
||||
this.allLock = new Mutex();
|
||||
this.latestLock = new Mutex();
|
||||
if (listMethod === "all") {
|
||||
this.listMethod = "all";
|
||||
} else if (listMethod === "latest") {
|
||||
this.listMethod = "latest";
|
||||
} else {
|
||||
this.listMethod = "auto";
|
||||
}
|
||||
}
|
||||
getAllBattleList() {
|
||||
return this.allLock.use(async ()=>{
|
||||
if (!this.allBattleList) {
|
||||
this.allBattleList = await this.splatnet.getAllBattleList();
|
||||
}
|
||||
return this.allBattleList;
|
||||
});
|
||||
}
|
||||
getLatestBattleList() {
|
||||
return this.latestLock.use(async ()=>{
|
||||
if (!this.latestBattleList) {
|
||||
this.latestBattleList = await this.splatnet.getBattleList();
|
||||
}
|
||||
return this.latestBattleList;
|
||||
});
|
||||
}
|
||||
async innerFetch(exporter) {
|
||||
if (this.listMethod === "latest") {
|
||||
return await exporter.notExported({
|
||||
type: "VsInfo",
|
||||
list: await this.getLatestBattleList()
|
||||
});
|
||||
}
|
||||
if (this.listMethod === "all") {
|
||||
return await exporter.notExported({
|
||||
type: "VsInfo",
|
||||
list: await this.getAllBattleList()
|
||||
});
|
||||
}
|
||||
if (this.listMethod === "auto") {
|
||||
const latestList = await exporter.notExported({
|
||||
type: "VsInfo",
|
||||
list: await this.getLatestBattleList()
|
||||
});
|
||||
if (latestList.length === 50) {
|
||||
return await exporter.notExported({
|
||||
type: "VsInfo",
|
||||
list: await this.getAllBattleList()
|
||||
});
|
||||
}
|
||||
return latestList;
|
||||
}
|
||||
throw new TypeError(`Unknown listMethod: ${this.listMethod}`);
|
||||
}
|
||||
async fetch(exporter) {
|
||||
return [
|
||||
...await this.innerFetch(exporter)
|
||||
].reverse();
|
||||
}
|
||||
}
|
||||
class CoopListFetcher {
|
||||
splatnet;
|
||||
constructor(splatnet){
|
||||
this.splatnet = splatnet;
|
||||
}
|
||||
async fetch(exporter) {
|
||||
return [
|
||||
...await exporter.notExported({
|
||||
type: "CoopInfo",
|
||||
list: await this.splatnet.getBattleList(BattleListType.Coop)
|
||||
})
|
||||
].reverse();
|
||||
}
|
||||
}
|
||||
function progress({ total , currentUrl , done }) {
|
||||
return {
|
||||
total,
|
||||
@@ -7041,6 +7225,7 @@ function progress({ total , currentUrl , done }) {
|
||||
};
|
||||
}
|
||||
class App {
|
||||
opts;
|
||||
profile;
|
||||
env;
|
||||
constructor(opts){
|
||||
@@ -7051,6 +7236,13 @@ class App {
|
||||
env: opts.env
|
||||
});
|
||||
this.env = opts.env;
|
||||
if (opts.listMethod && ![
|
||||
"all",
|
||||
"auto",
|
||||
"latest"
|
||||
].includes(opts.listMethod)) {
|
||||
throw new TypeError(`Unknown listMethod: ${opts.listMethod}`);
|
||||
}
|
||||
}
|
||||
getSkipMode() {
|
||||
const mode = this.opts.skipMode;
|
||||
@@ -7134,8 +7326,7 @@ class App {
|
||||
if (skipMode.includes("vs") || exporters.length === 0) {
|
||||
this.env.logger.log("Skip exporting VS games.");
|
||||
} else {
|
||||
this.env.logger.log("Fetching battle list...");
|
||||
const gameList = await splatnet.getBattleList();
|
||||
const gameListFetcher = new BattleListFetcher(this.opts.listMethod ?? "auto", splatnet);
|
||||
const { redraw , endBar } = this.exporterProgress("Export vs games");
|
||||
const fetcher = new GameFetcher({
|
||||
cache: this.opts.cache ?? new FileCache(this.profile.state.cacheDir),
|
||||
@@ -7147,7 +7338,7 @@ class App {
|
||||
type: "VsInfo",
|
||||
fetcher,
|
||||
exporter: e,
|
||||
gameList,
|
||||
gameListFetcher,
|
||||
stepProgress: stats[e.name],
|
||||
onStep: ()=>{
|
||||
redraw(e.name, progress(stats[e.name]));
|
||||
@@ -7171,8 +7362,7 @@ class App {
|
||||
if (skipMode.includes("coop") || exporters.length === 0) {
|
||||
this.env.logger.log("Skip exporting coop games.");
|
||||
} else {
|
||||
this.env.logger.log("Fetching coop battle list...");
|
||||
const coopBattleList = await splatnet.getBattleList(BattleListType.Coop);
|
||||
const gameListFetcher = new CoopListFetcher(splatnet);
|
||||
const { redraw , endBar } = this.exporterProgress("Export coop games");
|
||||
const fetcher = new GameFetcher({
|
||||
cache: this.opts.cache ?? new FileCache(this.profile.state.cacheDir),
|
||||
@@ -7183,7 +7373,7 @@ class App {
|
||||
type: "CoopInfo",
|
||||
fetcher,
|
||||
exporter: e,
|
||||
gameList: coopBattleList,
|
||||
gameListFetcher,
|
||||
stepProgress: stats[e.name],
|
||||
onStep: ()=>{
|
||||
redraw(e.name, progress(stats[e.name]));
|
||||
@@ -7259,14 +7449,9 @@ class App {
|
||||
await this.exportOnce();
|
||||
}
|
||||
}
|
||||
async exportGameList({ type , fetcher , exporter , gameList , stepProgress , onStep }) {
|
||||
async exportGameList({ type , fetcher , exporter , gameListFetcher , stepProgress , onStep }) {
|
||||
onStep?.();
|
||||
const workQueue = [
|
||||
...await exporter.notExported({
|
||||
type,
|
||||
list: gameList
|
||||
})
|
||||
].reverse();
|
||||
const workQueue = await gameListFetcher.fetch(exporter);
|
||||
const step = async (id)=>{
|
||||
const detail = await fetcher.fetch(type, id);
|
||||
const result = await exporter.exportGame(detail);
|
||||
@@ -7299,14 +7484,14 @@ class App {
|
||||
this.env.logger.log(`Skipped ${Object.entries(stats).map(([name, { skipped }])=>Object.entries(skipped).map(([reason, count])=>`${name}: ${reason} (${count})`).join(", "))}`);
|
||||
}
|
||||
}
|
||||
opts;
|
||||
}
|
||||
const parseArgs = (args)=>{
|
||||
const parsed = mod1.parse(args, {
|
||||
string: [
|
||||
"profilePath",
|
||||
"exporter",
|
||||
"skipMode"
|
||||
"skipMode",
|
||||
"listMethod"
|
||||
],
|
||||
boolean: [
|
||||
"help",
|
||||
@@ -7334,7 +7519,8 @@ const parseArgs = (args)=>{
|
||||
"s",
|
||||
"skip-mode"
|
||||
],
|
||||
"withSummary": "with-summary"
|
||||
"withSummary": "with-summary",
|
||||
"listMethod": "list-method"
|
||||
}
|
||||
});
|
||||
return parsed;
|
||||
@@ -7348,6 +7534,10 @@ Options:
|
||||
--exporter <exporter>, -e Exporter list to use (default: stat.ink)
|
||||
Multiple exporters can be separated by commas
|
||||
(e.g. "stat.ink,file")
|
||||
--list-method When set to "latest", the latest 50 matches will be obtained.
|
||||
When set to "all", matches of all modes will be obtained with a maximum of 250 matches (5 modes x 50 matches).
|
||||
When set to "auto", the latest 50 matches will be obtained. If 50 matches have not been uploaded yet, matches will be obtained from the list of all modes.
|
||||
"auto" is the default setting.
|
||||
--no-progress, -n Disable progress bar
|
||||
--monitor, -m Monitor mode
|
||||
--skip-mode <mode>, -s Skip mode (default: null)
|
||||
|
||||
Reference in new issue
Block a user