mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-15 09:48:14 +08:00
♻️ 变更目录,参考 TGAssistant 优化一些方法
This commit is contained in:
8
src/web/api/ENKA.ts
Normal file
8
src/web/api/ENKA.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @file web api ENKA.ts
|
||||
* @description ENKA API
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
export const ENKA_API = "https://enka.network/api/uid/"; // 基础 API
|
||||
13
src/web/api/Hk4e.ts
Normal file
13
src/web/api/Hk4e.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @file web api Hk4e.ts
|
||||
* @description 定义 Hk4e API
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
const Hk4eApi = "https://hk4e-api.mihoyo.com"; // 基础 API
|
||||
const Hk4eAnnoApi = `${Hk4eApi}/common/hk4e_cn/announcement/api`; // 公告 API
|
||||
export const Hk4eAnnoListApi = `${Hk4eAnnoApi}/getAnnList?`; // 公告列表 API
|
||||
export const Hk4eAnnoContentApi = `${Hk4eAnnoApi}/getAnnContent?`; // 公告内容 API
|
||||
export const Hk4eAnnoQuery =
|
||||
"game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=60&uid=500299765"; // 公告 Query
|
||||
14
src/web/api/Passport.ts
Normal file
14
src/web/api/Passport.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file web api Passport.ts
|
||||
* @description 定义 Passport API
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
const PassportApi = "https://passport-api.mihoyo.com/"; // 基础 API
|
||||
const PassportV4Api = "https://passport-api-v4.mihoyo.com/"; // 基础 API
|
||||
const PassportAuthApi = `${PassportApi}account/auth/api/`; // 认证 API
|
||||
|
||||
export const PassportTokenApi = `${PassportAuthApi}getLTokenBySToken`; // 根据 stoken 获取 ltoken
|
||||
export const PassportCookieTokenApi = `${PassportAuthApi}getCookieAccountInfoBySToken`; // 根据 Cookie 获取 Token
|
||||
export const PassportVerifyApi = `${PassportV4Api}account/ma-cn-session/web/verifyLtoken`; // 验证 stoken 有效性
|
||||
44
src/web/api/TGApi.ts
Normal file
44
src/web/api/TGApi.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @file web api TGApi.ts
|
||||
* @description 应用用到的 API
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
import { ENKA_API } from "./ENKA";
|
||||
import { Hk4eAnnoListApi, Hk4eAnnoContentApi, Hk4eAnnoQuery } from "./Hk4e";
|
||||
import { PassportTokenApi, PassportCookieTokenApi, PassportVerifyApi } from "./Passport";
|
||||
import {
|
||||
TakumiTokensApi, TakumiRecordCardApi,
|
||||
TakumiRecordGenshinCharacterApi, TakumiRecordGenshinIndexApi,
|
||||
TakumiRecordGenshinSpiralAbyssApi, TakumiSTokenBindingRolesApi,
|
||||
TakumiCookieBindingRolesApi,
|
||||
} from "./Takumi";
|
||||
|
||||
// 应用 API
|
||||
const TGApi = {
|
||||
GameAnnoList: Hk4eAnnoListApi, // 游戏公告 API
|
||||
GameAnnoContent: Hk4eAnnoContentApi, // 游戏公告内容 API
|
||||
GameAnnoQuery: Hk4eAnnoQuery, // 游戏公告 Query
|
||||
GameEnka: ENKA_API, // 游戏 ENKA API
|
||||
GameTokens: {
|
||||
getTokens: TakumiTokensApi, // 根据 login_ticket 获取游戏 Token
|
||||
getLToken: PassportTokenApi, // 根据 stoken 获取 ltoken
|
||||
getCookieToken: PassportCookieTokenApi, // 根据 Cookie 获取 Token
|
||||
verifyStoken: PassportVerifyApi, // 验证 stoken 有效性
|
||||
},
|
||||
GameData: {
|
||||
byCookie: {
|
||||
getAccounts: TakumiCookieBindingRolesApi, // 获取绑定角色
|
||||
getCharacter: TakumiRecordGenshinCharacterApi, // 获取角色信息
|
||||
},
|
||||
bySToken: {
|
||||
getAccounts: TakumiSTokenBindingRolesApi, // 获取绑定角色
|
||||
},
|
||||
getUserCard: TakumiRecordCardApi, // 获取用户卡片
|
||||
getUserBase: TakumiRecordGenshinIndexApi, // 获取用户基本信息
|
||||
getAbyss: TakumiRecordGenshinSpiralAbyssApi, // 获取深境螺旋信息
|
||||
},
|
||||
};
|
||||
|
||||
export default TGApi;
|
||||
21
src/web/api/Takumi.ts
Normal file
21
src/web/api/Takumi.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @file web api Takumi.ts
|
||||
* @description 定义 Takumi API
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
const TakumiApi = "https://api-takumi.mihoyo.com/"; // 基础 API
|
||||
const TakumiRecordApi = "https://api-takumi-record.mihoyo.com/"; // 游戏记录 API
|
||||
const TakumiBindingApi = `${TakumiApi}binding/api/`; // 绑定 API
|
||||
const TakumiRecordGenshinApi = `${TakumiRecordApi}game_record/app/genshin/api/`; // 原神游戏记录 API
|
||||
const TakumiAuthApi = `${TakumiApi}auth/api/`; // 认证 API
|
||||
|
||||
export const TakumiTokensApi = `${TakumiAuthApi}getMultiTokenByLoginTicket`; // 登录票据 API
|
||||
export const TakumiActionTicketsApi = `${TakumiAuthApi}getActionTicketByStoken`; // 行为票据 API
|
||||
export const TakumiRecordCardApi = `${TakumiRecordApi}game_record/app/card/wapi/getGameRecordCard`; // 游戏记录卡片 API
|
||||
export const TakumiRecordGenshinIndexApi = `${TakumiRecordGenshinApi}index`; // 原神游戏记录索引 API
|
||||
export const TakumiRecordGenshinCharacterApi = `${TakumiRecordGenshinApi}character`; // 原神游戏记录角色 API
|
||||
export const TakumiRecordGenshinSpiralAbyssApi = `${TakumiRecordGenshinApi}spiralAbyss`; // 原神游戏记录深境螺旋 API
|
||||
export const TakumiSTokenBindingRolesApi = `${TakumiBindingApi}getUserGameRolesBySToken`; // 获取绑定角色 API-根据 stoken
|
||||
export const TakumiCookieBindingRolesApi = `${TakumiBindingApi}getUserGameRolesByCookie`; // 获取绑定角色 API-根据 Cookie
|
||||
26
src/web/constant/TGConstant.ts
Normal file
26
src/web/constant/TGConstant.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @file web constant TGConstant.ts
|
||||
* @description 常量
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
import { BBS_VERSION, BBS_HEADER_AGENT, BBS_REFERER } from "./bbs";
|
||||
import SALT from "./salt";
|
||||
import SERVER from "./server";
|
||||
import { GAME_BIZ } from "./utils";
|
||||
|
||||
const TGConstant = {
|
||||
BBS: {
|
||||
VERSION: BBS_VERSION,
|
||||
USER_AGENT: BBS_HEADER_AGENT,
|
||||
REFERER: BBS_REFERER,
|
||||
},
|
||||
Salt: SALT,
|
||||
Server: SERVER,
|
||||
Utils: {
|
||||
GAME_BIZ,
|
||||
},
|
||||
};
|
||||
|
||||
export default TGConstant;
|
||||
10
src/web/constant/bbs.ts
Normal file
10
src/web/constant/bbs.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @file web constant bbs.ts
|
||||
* @description 常量-应用数据
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
export const BBS_VERSION = "2.49.1";
|
||||
export const BBS_HEADER_AGENT = `Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/${BBS_VERSION}`;
|
||||
export const BBS_REFERER = "https://webstatic.mihoyo.com";
|
||||
25
src/web/constant/salt.ts
Normal file
25
src/web/constant/salt.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @file web constant salt.ts
|
||||
* @description 用到的 salt 值
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description salt 值
|
||||
* @version 2.49.1
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
const SALT = {
|
||||
BBS: {
|
||||
K2: "egBrFMO1BPBG0UX5XOuuwMRLZKwTVKRV",
|
||||
LK2: "DG8lqMyc9gquwAUFc7zBS62ijQRX9XF7",
|
||||
},
|
||||
Other: {
|
||||
X4: "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
|
||||
X6: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
|
||||
prod: "JwYDpKvLj6MrMqqYU6jTKF17KNO2PXoS",
|
||||
},
|
||||
};
|
||||
|
||||
export default SALT;
|
||||
32
src/web/constant/server.ts
Normal file
32
src/web/constant/server.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file web constant server.ts
|
||||
* @description 服务器地址常量文件
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 服务器地址
|
||||
* @since Alpha v0.2.0
|
||||
* @enum {string}
|
||||
* @readonly
|
||||
* @property {string} CN_ISLAND 国服-天空岛
|
||||
* @property {string} CN_TREE 国服-世界树
|
||||
* @property {string} OS_USA 美服
|
||||
* @property {string} OS_EURO 欧服
|
||||
* @property {string} OS_ASIA 亚服
|
||||
* @property {string} OS_CHT 台服
|
||||
* @property {string} UNKNOWN 未知
|
||||
* @returns {string} 服务器地址
|
||||
*/
|
||||
enum SERVER {
|
||||
CN_ISLAND = "cn_gf01",
|
||||
CN_TREE = "cn_qd01",
|
||||
OS_USA = "os_usa",
|
||||
OS_EURO = "os_euro",
|
||||
OS_ASIA = "os_asia",
|
||||
OS_CHT = "os_cht",
|
||||
UNKNOWN = "unknown",
|
||||
};
|
||||
|
||||
export default SERVER;
|
||||
9
src/web/constant/utils.ts
Normal file
9
src/web/constant/utils.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @file web constant utils.ts
|
||||
* @description 一些杂项的常量
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
// game_biz
|
||||
export const GAME_BIZ = "hk4e_cn";
|
||||
41
src/web/request/TGRequest.ts
Normal file
41
src/web/request/TGRequest.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file core request TGRequest.ts
|
||||
* @description 应用用到的请求函数
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
import { getAnnoList, getAnnoContent } from "./getAnno";
|
||||
import {
|
||||
getTokensByLoginTicket, getLtokenBySToken,
|
||||
getCookieTokenBySToken, vetifySToken,
|
||||
} from "./getTokens";
|
||||
import {
|
||||
getGameCardByCookie, getGameAccountsByCookie,
|
||||
getAccountsBySToken, getGameRoleListByCookie,
|
||||
} from "./getGameData";
|
||||
|
||||
const TGRequest = {
|
||||
Anno: {
|
||||
getList: getAnnoList,
|
||||
getContent: getAnnoContent,
|
||||
},
|
||||
User: {
|
||||
byLoginTicket: {
|
||||
getLTokens: getTokensByLoginTicket,
|
||||
},
|
||||
byCookie: {
|
||||
getAccounts: getGameAccountsByCookie,
|
||||
getGameCard: getGameCardByCookie,
|
||||
getCharacter: getGameRoleListByCookie,
|
||||
},
|
||||
bySToken: {
|
||||
verify: vetifySToken,
|
||||
getLToken: getLtokenBySToken,
|
||||
getAccounts: getAccountsBySToken,
|
||||
getCookieToken: getCookieTokenBySToken,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default TGRequest;
|
||||
38
src/web/request/getAnno.ts
Normal file
38
src/web/request/getAnno.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file web request getAnnouncement.ts
|
||||
* @description 获取游戏内公告
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.2
|
||||
*/
|
||||
|
||||
// Tauri
|
||||
import { http } from "@tauri-apps/api";
|
||||
// Tauri.Genshin
|
||||
import TGApi from "../api/TGApi";
|
||||
|
||||
/**
|
||||
* @description 获取游戏内公告列表
|
||||
* @since Alpha v0.1.2
|
||||
* @returns {Promise<BTMuli.Genshin.Announcement.ListData>}
|
||||
*/
|
||||
export async function getAnnoList (): Promise<BTMuli.Genshin.Announcement.ListData> {
|
||||
return await http.fetch<BTMuli.Genshin.Announcement.ListResponse>(`${TGApi.GameAnnoList}${TGApi.GameAnnoQuery}`).then((res) => res.data.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取游戏内公告内容
|
||||
* @since Alpha v0.1.2
|
||||
* @param {number} annId 公告 ID
|
||||
* @returns {Promise<BTMuli.Genshin.Announcement.ContentItem>}
|
||||
*/
|
||||
export async function getAnnoContent (annId: number): Promise<BTMuli.Genshin.Announcement.ContentItem> {
|
||||
const annoContents: BTMuli.Genshin.Announcement.ContentItem[] = await http
|
||||
.fetch<BTMuli.Genshin.Announcement.ContentResponse>(`${TGApi.GameAnnoContent}${TGApi.GameAnnoQuery}`)
|
||||
.then((res) => res.data.data.list);
|
||||
const annoContent = annoContents.find((item) => item.ann_id === annId);
|
||||
if (annoContent) {
|
||||
return annoContent;
|
||||
} else {
|
||||
throw new Error("公告内容不存在");
|
||||
}
|
||||
}
|
||||
21
src/web/request/getEnkaData.ts
Normal file
21
src/web/request/getEnkaData.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @file web request getEnkaData.ts
|
||||
* @description 获取 ENKA 数据
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.3
|
||||
*/
|
||||
|
||||
// Tauri
|
||||
import { http } from "@tauri-apps/api";
|
||||
// Tauri.Genshin
|
||||
import TGApi from "../api/TGApi";
|
||||
|
||||
/**
|
||||
* @description 获取 ENKA 数据
|
||||
* @since Alpha v0.1.3
|
||||
* @param {number} uid 用户 UID
|
||||
* @returns {Promise<BTMuli.Genshin.Enka.Data>}
|
||||
*/
|
||||
export async function getEnkaData (uid: number): Promise<BTMuli.Genshin.Enka.Data> {
|
||||
return await http.fetch<BTMuli.Genshin.Enka.Data>(`${TGApi.GameEnka}${uid}`).then((res) => res.data);
|
||||
}
|
||||
101
src/web/request/getGameData.ts
Normal file
101
src/web/request/getGameData.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file core utils getGameData.ts
|
||||
* @description 获取游戏数据的函数
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
// tauri
|
||||
import { http } from "@tauri-apps/api";
|
||||
import qs from "qs";
|
||||
// utils
|
||||
import TGApi from "../api/TGApi";
|
||||
import TGUtils from "../utils/TGUtils";
|
||||
import TGConstant from "../constant/TGConstant";
|
||||
|
||||
/**
|
||||
* @description 获取用户游戏数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户的 Cookie
|
||||
* @param {string} uid 用户的 UID
|
||||
* @returns {Promise<unknown>} 用户基本信息
|
||||
*/
|
||||
export async function getGameCardByCookie (cookie: string, uid: string): Promise<unknown> {
|
||||
const url = `${TGApi.GameData.getUserCard}`;
|
||||
const params = { uid };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", qs.stringify(params), "common");
|
||||
console.log("header:", header);
|
||||
return await http.fetch(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
body: http.Body.json(params),
|
||||
}).then((res) => {
|
||||
console.log(res);
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取用户绑定角色-通过stoken
|
||||
* @since Alpha v0.2.0
|
||||
* @todo 暂时不考虑使用
|
||||
* @param {string} cookie 用户的 Cookie
|
||||
* @param {string} stoken stoken
|
||||
* @returns {Promise<unknown>} 用户绑定角色
|
||||
*/
|
||||
export async function getAccountsBySToken (cookie: string, stoken: string): Promise<unknown> {
|
||||
const url = TGApi.GameData.bySToken.getAccounts;
|
||||
// eslint-disable-next-line camelcase
|
||||
const params = { stoken, game_biz: TGConstant.Utils.GAME_BIZ };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", JSON.stringify(params), "common");
|
||||
return await http.fetch(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
body: http.Body.json(params),
|
||||
}).then((res) => {
|
||||
console.log(res.data);
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取用户绑定游戏账号-通过cookie
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户的 Cookie
|
||||
* @returns {Promise<BTMuli.Genshin.Base.Response| BTMuli.User.Game.Account[]>} 用户绑定角色
|
||||
*/
|
||||
export async function getGameAccountsByCookie (cookie: string): Promise<BTMuli.Genshin.Base.Response | BTMuli.User.Game.Account[]> {
|
||||
const url = TGApi.GameData.byCookie.getAccounts;
|
||||
const params = { game_biz: TGConstant.Utils.GAME_BIZ };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", qs.stringify(params), "common");
|
||||
return await http.fetch<BTMuli.User.Response.GameAccounts>(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
}).then((res) => {
|
||||
console.log(res.data);
|
||||
if (res.data.retcode !== 0) return res.data;
|
||||
return res.data.data.list;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取用户角色列表
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户的 Cookie
|
||||
* @param {string} uid 用户 uid
|
||||
* @returns {Promise<unknown>} 用户角色列表
|
||||
*/
|
||||
export async function getGameRoleListByCookie (cookie: string, uid: string): Promise<unknown> {
|
||||
const url = TGApi.GameData.byCookie.getCharacter;
|
||||
// eslint-disable-next-line camelcase
|
||||
const data = { role_id: uid, server: TGUtils.Tools.getServerByUid(uid) };
|
||||
const header = TGUtils.User.getHeader(cookie, "", JSON.stringify(data), "common");
|
||||
return await http.fetch(url, {
|
||||
method: "POST",
|
||||
headers: header,
|
||||
body: http.Body.json(data),
|
||||
}).then((res) => {
|
||||
console.log(res.data);
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
107
src/web/request/getTokens.ts
Normal file
107
src/web/request/getTokens.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file web request getTokens.ts
|
||||
* @description 获取游戏 Token
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
// tauri
|
||||
import { http } from "@tauri-apps/api";
|
||||
// Node
|
||||
import qs from "qs";
|
||||
// api
|
||||
import TGApi from "../api/TGApi";
|
||||
// utils
|
||||
import TGUtils from "../utils/TGUtils";
|
||||
|
||||
/**
|
||||
* @description 根据 login_ticket 获取游戏 Token,包括 stoken 和 ltoken
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie cookie
|
||||
* @param {string} ticket 登录票证
|
||||
* @param {string} uid 登录用户 uid
|
||||
* @returns {Promise<BTMuli.User.Base.TokenItem[] | BTMuli.Genshin.Base.Response>}
|
||||
*/
|
||||
// eslint-disable-next-line camelcase
|
||||
export async function getTokensByLoginTicket (cookie: string, ticket: string, uid: string): Promise<BTMuli.User.Base.TokenItem[] | BTMuli.Genshin.Base.Response> {
|
||||
// eslint-disable-next-line camelcase
|
||||
const url = `${TGApi.GameTokens.getTokens}?login_ticket=${ticket}&token_types=3&uid=${uid}`;
|
||||
// eslint-disable-next-line camelcase
|
||||
const param = { login_ticket: ticket, token_types: 3, uid };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", qs.stringify(param), "common");
|
||||
console.log("header:", header);
|
||||
return await http.fetch<BTMuli.User.Response.Token>(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
}).then((res) => {
|
||||
console.log(res);
|
||||
if (res.data.retcode !== 0) return res.data;
|
||||
return res.data.data.list;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据 stoken 获取 ltoken
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户 Cookie
|
||||
* @param {string} stoken stoken
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
export async function getLtokenBySToken (cookie: string, stoken: string): Promise<unknown> {
|
||||
const url = TGApi.GameTokens.getLToken;
|
||||
const params = { stoken };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", qs.stringify(params), "common");
|
||||
console.log("header:", header);
|
||||
return await http.fetch<BTMuli.User.Response.Token>(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
body: http.Body.json(params),
|
||||
}).then((res) => {
|
||||
console.log(res);
|
||||
if (res.data.retcode !== 0) return res.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据 stoken 获取 cookieToken
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户 Cookie
|
||||
* @param {string} stoken stoken
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
export async function getCookieTokenBySToken (cookie: string, stoken: string): Promise<unknown> {
|
||||
const url = TGApi.GameTokens.getCookieToken;
|
||||
const params = { stoken };
|
||||
const header = TGUtils.User.getHeader(cookie, "GET", qs.stringify(params), "common");
|
||||
console.log("header:", header);
|
||||
return await http.fetch(url, {
|
||||
method: "GET",
|
||||
headers: header,
|
||||
body: http.Body.json(params),
|
||||
}).then((res) => {
|
||||
console.log(res.data);
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 验证 stoken 有效性
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie 用户 Cookie
|
||||
* @param {string} stoken stoken
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
export async function verifySToken (cookie: string, stoken: string): Promise<unknown> {
|
||||
const url = TGApi.GameTokens.verifyStoken;
|
||||
const data = { stoken };
|
||||
const header = TGUtils.User.getHeader(cookie, "POST", qs.stringify(data), "common");
|
||||
console.log("header:", header);
|
||||
return await http.fetch(url, {
|
||||
method: "POST",
|
||||
headers: header,
|
||||
body: http.Body.json(data),
|
||||
}).then((res) => {
|
||||
console.log(res.data);
|
||||
return res.data;
|
||||
});
|
||||
}
|
||||
27
src/web/utils/TGUtils.ts
Normal file
27
src/web/utils/TGUtils.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file web utils TGUtils.ts
|
||||
* @description 应用用到的工具函数
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
import { parseAnnoContent } from "./parseAnno";
|
||||
import { getAnnoCard } from "./getAnnoCard";
|
||||
import { getRequestHeader } from "./getRequestHeader";
|
||||
import { cookieToString, getServerByUid } from "./tools";
|
||||
|
||||
const TGUtils = {
|
||||
Anno: {
|
||||
getCard: getAnnoCard,
|
||||
parseContent: parseAnnoContent,
|
||||
},
|
||||
User: {
|
||||
getHeader: getRequestHeader,
|
||||
},
|
||||
Tools: {
|
||||
cookieToString,
|
||||
getServerByUid,
|
||||
},
|
||||
};
|
||||
|
||||
export default TGUtils;
|
||||
34
src/web/utils/getAnnoCard.ts
Normal file
34
src/web/utils/getAnnoCard.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @file web utils transAnno.ts
|
||||
* @description 公告数据转换工具
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.2
|
||||
*/
|
||||
|
||||
// 默认封面图
|
||||
const defaultCover = "/source/UI/defaultCover.webp";
|
||||
|
||||
/**
|
||||
* @description 将获取到的数据转为渲染用的卡片
|
||||
* @since Alpha v0.1.2
|
||||
* @param {BTMuli.Genshin.Announcement.ListData} data 公告数据
|
||||
* @returns {BTMuli.Genshin.Announcement.ListCard[]} 渲染用的卡片
|
||||
*/
|
||||
export function getAnnoCard (data: BTMuli.Genshin.Announcement.ListData): BTMuli.Genshin.Announcement.ListCard[] {
|
||||
const cards: BTMuli.Genshin.Announcement.ListCard[] = [];
|
||||
data.list.map((annoList: BTMuli.Genshin.Announcement) => {
|
||||
return annoList.list.map((anno: BTMuli.Genshin.Announcement.ListItem) => {
|
||||
return cards.push({
|
||||
id: anno.ann_id,
|
||||
title: anno.title,
|
||||
subtitle: anno.subtitle,
|
||||
banner: anno.banner || defaultCover,
|
||||
typeLabel: anno.type_label,
|
||||
tagIcon: anno.tag_icon,
|
||||
startTime: anno.start_time,
|
||||
endTime: anno.end_time,
|
||||
});
|
||||
});
|
||||
});
|
||||
return cards;
|
||||
}
|
||||
53
src/web/utils/getDS.ts
Normal file
53
src/web/utils/getDS.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @file web utils getDS.ts
|
||||
* @description ds 算法
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
// Node
|
||||
import md5 from "js-md5";
|
||||
import qs from "qs";
|
||||
// Tauri.Genshin
|
||||
import { random } from "./tools";
|
||||
import TGConstant from "../constant/TGConstant";
|
||||
|
||||
/**
|
||||
* @description 获取 salt
|
||||
* @since Alpha v0.2.0
|
||||
* @version 2.49.1
|
||||
* @param {string} saltType salt 类型
|
||||
* @returns {string} salt
|
||||
*/
|
||||
function getSalt (saltType: string) {
|
||||
switch (saltType) {
|
||||
case "common":
|
||||
return TGConstant.Salt.Other.X4;
|
||||
case "prod":
|
||||
return TGConstant.Salt.Other.prod;
|
||||
default:
|
||||
return TGConstant.Salt.Other.X4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取 ds
|
||||
* @since Alpha v0.2.0
|
||||
* @version 2.49.1
|
||||
* @param {string} saltType salt 类型
|
||||
* @param {string} method 请求方法
|
||||
* @param {string} data 请求数据
|
||||
* @returns {string} ds
|
||||
*/
|
||||
export function getDS (method: string, data: string, saltType: string): string {
|
||||
const salt = getSalt(saltType);
|
||||
const params = {
|
||||
salt,
|
||||
t: Math.floor(Date.now() / 1000).toString(),
|
||||
r: random(100000, 200000).toString(),
|
||||
b: method === "GET" ? "" : data,
|
||||
q: method === "GET" ? data : "",
|
||||
};
|
||||
const md5Str = md5.update(qs.stringify(params)).hex();
|
||||
return `${params.t},${params.r},${md5Str}`;
|
||||
}
|
||||
29
src/web/utils/getRequestHeader.ts
Normal file
29
src/web/utils/getRequestHeader.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @file web utils getRequestHeader.ts
|
||||
* @description 获取请求头
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
import TGConstant from "../constant/TGConstant";
|
||||
import { getDS } from "./getDS";
|
||||
|
||||
/**
|
||||
* @description 获取请求头
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} cookie cookie
|
||||
* @param {string} method 请求方法
|
||||
* @param {string} data 请求数据
|
||||
* @param {string} saltType salt 类型
|
||||
* @returns {Record<string, string>} 请求头
|
||||
*/
|
||||
export function getRequestHeader (cookie: string, method: string, data: string, saltType: string): Record<string, string> {
|
||||
return {
|
||||
"User-Agent": TGConstant.BBS.USER_AGENT,
|
||||
"x-rpc-app_version": TGConstant.BBS.VERSION,
|
||||
"x-rpc-client_type": "5",
|
||||
Referer: "https://webstatic.mihoyo.com/",
|
||||
DS: getDS(method, data, saltType),
|
||||
Cookie: cookie,
|
||||
};
|
||||
}
|
||||
61
src/web/utils/parseAnno.ts
Normal file
61
src/web/utils/parseAnno.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file web utils parseAnno.ts
|
||||
* @description 解析游戏内公告数据
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.1.2
|
||||
*/
|
||||
|
||||
import { decodeRegExp } from "./tools";
|
||||
|
||||
/**
|
||||
* @description 解析游戏内公告数据
|
||||
* @since Alpha v0.1.2
|
||||
* @param {string} data 游戏内公告数据
|
||||
* @returns {string} 解析后的数据
|
||||
*/
|
||||
export function parseAnnoContent (data: string): string {
|
||||
const htmlBase = new DOMParser().parseFromString(data, "text/html");
|
||||
htmlBase.querySelectorAll("span").forEach((span) => {
|
||||
if (span.style.fontSize) {
|
||||
span.style.fontSize = "";
|
||||
}
|
||||
if (span.children.length === 0) {
|
||||
return (span.innerHTML = decodeRegExp(span.innerHTML));
|
||||
} else {
|
||||
span.querySelectorAll("*").forEach((child) => {
|
||||
if (child.children.length === 0) {
|
||||
return (child.innerHTML = decodeRegExp(child.innerHTML));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
htmlBase.querySelectorAll("p").forEach((p) => {
|
||||
if (p.children.length === 0) {
|
||||
return (p.innerHTML = decodeRegExp(p.innerHTML));
|
||||
} else {
|
||||
p.querySelectorAll("*").forEach((child) => {
|
||||
if (child.children.length === 0) {
|
||||
return (child.innerHTML = decodeRegExp(child.innerHTML));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
htmlBase.querySelectorAll("img").forEach((img) => {
|
||||
img.style.maxWidth = "100%";
|
||||
img.style.borderRadius = "10px";
|
||||
img.style.margin = "10px 0";
|
||||
});
|
||||
htmlBase.querySelectorAll("a").forEach((a) => {
|
||||
const span = htmlBase.createElement("i");
|
||||
span.classList.add("mdi", "mdi-link-variant", "anno-link-icon");
|
||||
a.prepend(span);
|
||||
if (a.href.startsWith("javascript:miHoYoGameJSSDK.openInBrowser")) {
|
||||
a.href = a.href.replace("javascript:miHoYoGameJSSDK.openInBrowser('", "").replace("');", "");
|
||||
a.target = "_blank";
|
||||
} else if (a.href.startsWith("javascript:miHoYoGameJSSDK.openInWebview")) {
|
||||
a.href = a.href.replace("javascript:miHoYoGameJSSDK.openInWebview('", "").replace("');", "");
|
||||
a.target = "_blank";
|
||||
}
|
||||
});
|
||||
return htmlBase.body.innerHTML;
|
||||
}
|
||||
107
src/web/utils/tools.ts
Normal file
107
src/web/utils/tools.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file web utils tools.ts
|
||||
* @description 应用用到的工具函数
|
||||
* @author BTMuli<bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
// Node
|
||||
import { stringify } from "qs";
|
||||
// TauriGenshin
|
||||
import TGConstant from "../constant/TGConstant";
|
||||
|
||||
/**
|
||||
* @description 转义正则表达式
|
||||
* @since Alpha v0.1.2
|
||||
* @param {string} data 内容
|
||||
* @returns {string} 转义后的内容
|
||||
*/
|
||||
export function decodeRegExp (data: string): string {
|
||||
let res = data;
|
||||
if (res.length === 0) return res;
|
||||
res = res.replace(/</g, "<");
|
||||
res = res.replace(/>/g, ">");
|
||||
res = res.replace(/ /g, " ");
|
||||
res = res.replace(/'/g, "'");
|
||||
res = res.replace(/"/g, "\"");
|
||||
res = res.replace(/'/g, "'");
|
||||
res = res.replace(/&/g, "&");
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取随机字符串
|
||||
* @since Alpha v0.2.0
|
||||
* @param {number} length 字符串长度
|
||||
* @returns {string} 随机字符串
|
||||
*/
|
||||
export function getRandomString (length: number): string {
|
||||
const str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
let res = "";
|
||||
for (let i = 0; i < length; i++) {
|
||||
res += str[Math.floor(Math.random() * str.length)];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取随机数
|
||||
* @since Alpha v0.2.0
|
||||
* @param {number} min 最小值
|
||||
* @param {number} max 最大值
|
||||
* @returns {number} 随机数
|
||||
*/
|
||||
export function random (min: number, max: number): number {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description object 转换为 query string
|
||||
* @since Alpha v0.2.0
|
||||
* @param {Record<string, string>} obj object
|
||||
* @param {boolean} encode 是否编码
|
||||
* @returns {string} query string
|
||||
*/
|
||||
export function qs (obj: Record<string, string>, encode: boolean = false): string {
|
||||
let res = "";
|
||||
for (const [k, v] of Object.entries(obj)) res += `${k}=${encode ? encodeURIComponent(v) : v}&`;
|
||||
res = res.slice(0, res.length - 1);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将 ck JSON 对象转换为字符串
|
||||
* @since Alpha v0.2.0
|
||||
* @param {object} ck ck JSON 对象
|
||||
* @returns {string} ck 字符串
|
||||
*/
|
||||
export function cookieToString (ck: object): string {
|
||||
let res = stringify(ck);
|
||||
res = res.replace(/&/g, ";");
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据 uid 获取 server
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} uid uid
|
||||
* @returns {string} server
|
||||
*/
|
||||
export function getServerByUid (uid: string): string {
|
||||
// 获取第一个字符
|
||||
const first = uid[0];
|
||||
// 1-4 为国服-天空岛
|
||||
if (first >= "1" && first <= "4") return TGConstant.Server.CN_ISLAND;
|
||||
// 5 为国服-世界树
|
||||
if (first === "5") return TGConstant.Server.CN_TREE;
|
||||
// 6 为美服
|
||||
if (first === "6") return TGConstant.Server.OS_USA;
|
||||
// 7 为欧服
|
||||
if (first === "7") return TGConstant.Server.OS_EURO;
|
||||
// 8 为亚服
|
||||
if (first === "8") return TGConstant.Server.OS_ASIA;
|
||||
// 9 为台服
|
||||
if (first === "9") return TGConstant.Server.OS_CHT;
|
||||
// 其他情况返回未知
|
||||
return TGConstant.Server.UNKNOWN;
|
||||
}
|
||||
Reference in New Issue
Block a user