♻️ 姑且能跑 dev,尚需调试功能

This commit is contained in:
目棃
2024-07-02 23:05:33 +08:00
parent 1214501691
commit 367307029b
66 changed files with 12626 additions and 2887 deletions

View File

@@ -40,7 +40,7 @@
"prettier --write"
],
"*.rs": [
"cargo fmt"
"rustfmt"
]
},
"keywords": [
@@ -67,12 +67,17 @@
"dependencies": {
"@mdi/font": "7.4.47",
"@tauri-apps/api": "2.0.0-beta.14",
"@tauri-apps/plugin-deep-link": "2.0.0-beta.7",
"@tauri-apps/plugin-dialog": "2.0.0-beta.5",
"@tauri-apps/plugin-fs": "2.0.0-beta.5",
"@tauri-apps/plugin-http": "2.0.0-beta.6",
"@tauri-apps/plugin-os": "2.0.0-beta.6",
"@tauri-apps/plugin-shell": "2.0.0-beta.6",
"ajv": "^8.16.0",
"artplayer": "^5.1.6",
"clipboard": "^2.0.11",
"color-convert": "^2.0.1",
"echarts": "^5.5.0",
"echarts": "^5.5.1",
"html2canvas": "^1.4.1",
"js-md5": "^0.8.3",
"pinia": "^2.1.7",
@@ -81,7 +86,7 @@
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log#v2",
"tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v2",
"uuid": "^10.0.0",
"vue": "^3.4.30",
"vue": "^3.4.31",
"vue-echarts": "^6.7.3",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.4.0",
@@ -91,30 +96,30 @@
},
"devDependencies": {
"@eslint/eslintrc": "^3.1.0",
"@eslint/js": "^9.5.0",
"@eslint/js": "^9.6.0",
"@tauri-apps/cli": "2.0.0-beta.21",
"@types/color-convert": "^2.0.3",
"@types/js-md5": "^0.7.2",
"@types/node": "^20.14.9",
"@types/uuid": "^10.0.0",
"@typescript-eslint/parser": "^7.14.1",
"@typescript-eslint/parser": "^7.15.0",
"@vitejs/plugin-vue": "^5.0.5",
"concurrently": "^8.2.2",
"eslint": "^9.5.0",
"eslint": "^9.6.0",
"eslint-config-love": "^53.0.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsonc": "^2.16.0",
"eslint-plugin-n": "^17.9.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-promise": "^6.2.0",
"eslint-plugin-vue": "^9.26.0",
"eslint-plugin-promise": "^6.4.0",
"eslint-plugin-vue": "^9.27.0",
"eslint-plugin-yml": "^1.14.0",
"globals": "^15.6.0",
"globals": "^15.7.0",
"husky": "^9.0.11",
"jsonc-eslint-parser": "^2.4.0",
"lint-staged": "^15.2.7",
"oxlint": "^0.4.4",
"oxlint": "^0.5.1",
"prettier": "3.3.2",
"stylelint": "^16.6.1",
"stylelint-config-idiomatic-order": "^10.0.0",
@@ -123,10 +128,10 @@
"stylelint-high-performance-animation": "^1.10.0",
"stylelint-order": "^6.0.4",
"stylelint-prettier": "^5.0.0",
"typescript": "^5.5.2",
"typescript-eslint": "^7.14.1",
"vite": "^5.3.1",
"vite-plugin-vue-devtools": "^7.3.4",
"typescript": "^5.5.3",
"typescript-eslint": "^7.15.0",
"vite": "^5.3.2",
"vite-plugin-vue-devtools": "^7.3.5",
"vite-plugin-vuetify": "^2.0.3",
"vue-eslint-parser": "^9.4.3",
"yaml-eslint-parser": "^1.2.3"

983
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

876
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -17,27 +17,47 @@ chrono = "0.4.38"
log = "0.4.21"
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117"
tauri = "2.0.0-beta.23"
tauri = { version = "2.0.0-beta.23", features = [] }
tauri-utils = "2.0.0-beta.18"
url = "2.5.1"
walkdir = "2.5.0"
# sqlite 插件
[dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
features = ["sqlite"]
# deep link 插件
[dependencies.tauri-plugin-deep-link]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# dialog 插件
[dependencies.tauri-plugin-dialog]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# fs 插件
[dependencies.tauri-plugin-fs]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# http 插件
[dependencies.tauri-plugin-http]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# log 插件
[dependencies.tauri-plugin-log]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# os 插件
[dependencies.tauri-plugin-os]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
# sqlite 插件
[dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace"
branch = "v2"
features = ["sqlite"]
[features]
# this feature is used for production builds or when `devPath` points to the filesystem
# DO NOT REMOVE!!

View File

@@ -0,0 +1,11 @@
{
"$schema": "./schemas/desktop-schema.json",
"identifier": "Mys",
"description": "Capability for the mys client window",
"windows": ["mhy_client"],
"permissions": [],
"remote": {
"urls": ["https://*.mihoyo.com/*", "https://*.miyoushe.com/*"]
},
"platforms": ["windows", "macOS"]
}

View File

@@ -0,0 +1,32 @@
{
"$schema": "./schemas/desktop-schema.json",
"identifier": "TeyvatGuide",
"description": "Capability for the main window",
"windows": ["TeyvatGuide"],
"permissions": [
"path:allow-resolve-directory",
"path:default",
"event:allow-listen",
"event:default",
"app:allow-version",
"app:default",
"window:allow-set-title",
"sql:allow-load",
"sql:default",
"sql:allow-execute",
"log:allow-log",
"log:default",
"http:allow-fetch",
{
"identifier": "http:default",
"allow": [
{
"url": "https://*.miyoushe.com/*"
},
{
"url": "https://*.mihoyo.com/*"
}
]
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -1 +1,36 @@
{}
{
"Mys": {
"identifier": "Mys",
"description": "Capability for the mys client window",
"remote": { "urls": ["https://*.mihoyo.com/*", "https://*.miyoushe.com/*"] },
"local": true,
"windows": ["mhy_client"],
"permissions": [],
"platforms": ["windows", "macOS"]
},
"TeyvatGuide": {
"identifier": "TeyvatGuide",
"description": "Capability for the main window",
"local": true,
"windows": ["TeyvatGuide"],
"permissions": [
"path:allow-resolve-directory",
"path:default",
"event:allow-listen",
"event:default",
"app:allow-version",
"app:default",
"window:allow-set-title",
"sql:allow-load",
"sql:default",
"sql:allow-execute",
"log:allow-log",
"log:default",
"http:allow-fetch",
{
"identifier": "http:default",
"allow": [{ "url": "https://*.miyoushe.com/*" }, { "url": "https://*.mihoyo.com/*" }]
}
]
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
//! @file src/client/menu.rs
//! @desc 客户端菜单模块,负责操作米游社客户端菜单
//! @since Beta v0.4.10
//! @since Beta v0.5.0
use tauri::menu::{Menu, MenuBuilder, MenuEvent, MenuItemBuilder, Submenu, SubmenuBuilder};
use tauri::{AppHandle, LogicalSize, Manager, Size, Window, Wry};

View File

@@ -1,6 +1,6 @@
//! @file src/client/mod.rs
//! @desc 客户端模块,负责操作米游社客户端
//! @since Beta v0.4.10
//! @since Beta v0.5.0
mod menu;
use tauri::async_runtime::block_on;

View File

@@ -1,27 +1,26 @@
//! @file src/commands.rs
//! @desc 命令模块,负责处理命令
//! @since Beta v0.4.10
//! @since Beta v0.5.0
use tauri::{Manager, WebviewWindowBuilder};
use tauri::{AppHandle, Manager, WebviewWindowBuilder};
use tauri_utils::config::WindowConfig;
// 放一个常数,用来判断应用是否初始化
static mut APP_INITIALIZED: bool = false;
static mut DEEP_LINK_REGISTERED: bool = false;
// 初始化应用
#[tauri::command]
pub async fn init_app(app_handle: tauri::AppHandle) {
pub async fn init_app(app_handle: AppHandle) {
unsafe {
if APP_INITIALIZED == true && DEEP_LINK_REGISTERED == true {
if APP_INITIALIZED == true {
return;
}
}
dbg!("init_app");
let _mhy = app_handle.get_webview_window("mhy_client");
if _mhy.is_some() {
std::thread::sleep(std::time::Duration::from_millis(1000));
_mhy.unwrap().close().unwrap();
// todo 这里应该延时,否则可能造成 macOS 平台的崩溃
// _mhy.unwrap().close().unwrap();
}
app_handle.emit("initApp", ()).unwrap();
unsafe {

View File

@@ -1,6 +1,6 @@
//! @file src/main.rs
//! @desc 主模块,用于启动应用
//! @since Beta v0.4.10
//! @since Beta v0.5.0
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
@@ -35,9 +35,13 @@ fn window_event_handler(app: &tauri::Window, event: &tauri::WindowEvent) {
fn main() {
tauri::Builder::default()
.on_window_event(move |app, event| window_event_handler(app, event))
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(plugins::build_sql_plugin())
.plugin(plugins::build_log_plugin())
.plugin(tauri_plugin_deep_link::init())
.setup(|_app| {
let _window = _app.get_webview_window("TeyvatGuide");
#[cfg(debug_assertions)]

View File

@@ -1,6 +1,6 @@
//! @file src/plugins.rs
//! @desc 插件模块,用于注册插件
//! @since Beta v0.4.10
//! @since Beta v0.5.0
use super::utils;
use log::LevelFilter;

View File

@@ -26,11 +26,7 @@
"icons/icon.ico",
"icons/icon.png"
],
"targets": [
"msi",
"app",
"dmg"
],
"targets": ["msi", "app", "dmg"],
"windows": {
"wix": {
"language": "zh-CN"
@@ -66,35 +62,15 @@
}
],
"security": {
"capabilities": [
{
"identifier": "TeyvatGuide",
"description": "米游社客户端",
"windows": [
"mhy_client"
],
"permissions": [],
"remote": {
"urls": [
"https://*.mihoyo.com/*",
"https://*.miyoushe.com/*"
]
},
"platforms": [
"windows",
"macOS"
]
}
]
"capabilities": ["TeyvatGuide", "Mys"]
}
},
"plugins": {
"deep-link": {
"desktop": {
"schemes": [
"teyvatguide"
]
}
"schemes": ["teyvatguide"]
},
"mobile": []
}
}
}

View File

@@ -11,8 +11,9 @@
</template>
<script lang="ts" setup>
import { app, event, fs, tauri, window as TauriWindow } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/helpers/event";
import { app, event, core, window as TauriWindow } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/event";
import { mkdir } from "@tauri-apps/plugin-fs";
import { storeToRefs } from "pinia";
import { computed, onBeforeMount, onMounted, onUnmounted, ref } from "vue";
import { useRouter } from "vue-router";
@@ -46,15 +47,15 @@ onBeforeMount(async () => {
if (isMain.value) {
const title = "Teyvat Guide v" + (await app.getVersion()) + " Beta";
await win.setTitle(title);
await listenOnInit();
await tauri.invoke("init_app");
listenOnInit();
await core.invoke("init_app");
urlListener = await getDeepLink();
}
});
onMounted(async () => {
onMounted(() => {
document.documentElement.className = theme.value;
themeListener = await event.listen("readTheme", async (e: Event<string>) => {
themeListener = event.listen("readTheme", async (e: Event<string>) => {
const themeGet = e.payload;
if (theme.value !== themeGet) {
theme.value = themeGet;
@@ -64,9 +65,9 @@ onMounted(async () => {
});
// 启动后只执行一次的监听
async function listenOnInit(): Promise<void> {
await event.listen("initApp", async () => {
await tauri.invoke("register_deep_link");
function listenOnInit(): void {
console.info("[App][listenOnInit] 监听初始化事件!");
event.listen("initApp", async () => {
await checkAppLoad();
await checkDeviceFp();
try {
@@ -78,7 +79,6 @@ async function listenOnInit(): Promise<void> {
}
await checkUpdate();
});
return;
}
async function checkAppLoad(): Promise<void> {
@@ -166,7 +166,7 @@ async function checkUserLoad(): Promise<void> {
return;
}
if (userDir !== appStore.userDir) appStore.userDir = userDir;
await fs.createDir(appStore.userDir, { recursive: true });
await mkdir(appStore.userDir, { recursive: true });
}
async function getDeepLink(): Promise<UnlistenFn> {

View File

@@ -243,7 +243,7 @@
<script lang="ts" setup>
import { event, window as TauriWindow } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/helpers/event";
import { UnlistenFn, Event } from "@tauri-apps/api/event";
import { storeToRefs } from "pinia";
import { computed, onMounted, onUnmounted, ref, watch } from "vue";

View File

@@ -9,7 +9,7 @@
</template>
<script lang="ts" setup>
import { event } from "@tauri-apps/api";
import { UnlistenFn, Event } from "@tauri-apps/api/helpers/event";
import { UnlistenFn, Event } from "@tauri-apps/api/event";
import { computed, onMounted, onUnmounted } from "vue";
import { useAppStore } from "../../store/modules/app.js";
@@ -25,8 +25,8 @@ const themeGet = computed({
});
let themeListener: UnlistenFn;
onMounted(async () => {
themeListener = await listenOnTheme();
onMounted(() => {
themeListener = listenOnTheme();
});
async function switchTheme(): Promise<void> {
@@ -34,8 +34,8 @@ async function switchTheme(): Promise<void> {
await event.emit("readTheme", themeGet.value);
}
async function listenOnTheme(): Promise<UnlistenFn> {
return await event.listen("readTheme", (e: Event<string>) => {
function listenOnTheme(): UnlistenFn {
return event.listen("readTheme", (e: Event<string>) => {
const theme = e.payload;
themeGet.value = theme === "default" ? "default" : "dark";
});

View File

@@ -42,8 +42,9 @@
</v-list>
</template>
<script lang="ts" setup>
import { dialog, fs, path } from "@tauri-apps/api";
import { FileEntry } from "@tauri-apps/api/fs";
import { path } from "@tauri-apps/api";
import { open } from "@tauri-apps/plugin-dialog";
import { readDir, remove } from "@tauri-apps/plugin-fs";
import TGSqlite from "../../plugins/Sqlite/index.js";
import { useAppStore } from "../../store/modules/app.js";
@@ -67,7 +68,7 @@ async function confirmCUD(): Promise<void> {
});
return;
}
const dir = await dialog.open({
const dir: string | null = await open({
directory: true,
defaultPath: oriDir,
multiple: false,
@@ -79,13 +80,6 @@ async function confirmCUD(): Promise<void> {
});
return;
}
if (typeof dir !== "string") {
showSnackbar({
color: "error",
text: "路径错误!",
});
return;
}
if (dir === oriDir) {
showSnackbar({
color: "warn",
@@ -96,7 +90,7 @@ async function confirmCUD(): Promise<void> {
appStore.userDir = dir;
await TGSqlite.saveAppData("userDir", dir);
await backUpUserData(dir);
await fs.removeDir(oriDir, { recursive: true });
await remove(oriDir, { recursive: true });
showSnackbar({
text: "已重新备份数据!即将刷新页面!",
timeout: 3000,
@@ -127,11 +121,11 @@ async function confirmCLD(): Promise<void> {
return;
}
const logDir = appStore.logDir;
const files = await fs.readDir(logDir);
const delFiles = files.filter((file: FileEntry) => {
const files = await readDir(logDir);
const delFiles = files.filter((file) => {
// yyyy-mm-dd.log
const reg = /(\d{4}-\d{2}-\d{2}\.log)/;
const match = file.path.match(reg);
const match = file.name.match(reg);
if (!Array.isArray(match) || match.length < 1) return false;
const date = match[1].replace(".log", "");
return isOverWeek(date);
@@ -144,7 +138,8 @@ async function confirmCLD(): Promise<void> {
return;
}
for (const file of delFiles) {
await fs.removeFile(file.path);
const filePath = `${logDir}/${file.name}`;
await remove(filePath);
}
showSnackbar({
text: `已清理 ${delFiles.length} 个日志文件!`,

View File

@@ -77,7 +77,7 @@ async function toWebLogin(): Promise<void> {
return;
}
await TGClient.open("config_sign_in", "https://user.mihoyo.com");
signListener = await event.listen("config_user_sign", async (e: Event<unknown>) => {
signListener = event.listen("config_user_sign", async (e: Event<unknown>) => {
if (typeof e.payload !== "string") {
showSnackbar({
color: "error",

View File

@@ -28,8 +28,7 @@
</TOverlay>
</template>
<script setup lang="ts">
import { http } from "@tauri-apps/api";
import { ResponseType } from "@tauri-apps/api/http";
import { fetch } from "@tauri-apps/plugin-http";
import { computed, onMounted, ref, watch } from "vue";
import { xml2json } from "xml-js";
@@ -166,11 +165,10 @@ async function loadText(): Promise<void> {
async function parseXml(link: string) {
try {
const res = await http.fetch<string>(link, {
method: "GET",
responseType: ResponseType.Text,
});
return JSON.parse(xml2json(res.data));
const response = await fetch(link, { method: "GET" });
const data = await response.arrayBuffer();
const xml = new TextDecoder("utf-8").decode(data);
return JSON.parse(xml2json(xml));
} catch (error) {
console.error(error);
return false;

View File

@@ -40,7 +40,7 @@
</template>
<script lang="ts" setup>
import { event } from "@tauri-apps/api";
import { UnlistenFn } from "@tauri-apps/api/helpers/event";
import { UnlistenFn } from "@tauri-apps/api/event";
import { onMounted, onUnmounted, ref } from "vue";
import { saveImgLocal } from "../../utils/TGShare.js";
@@ -59,7 +59,7 @@ const iconDark = ref<string>();
const offer = ref<string>();
onMounted(async () => {
themeListener = await event.listen("readTheme", (e) => {
themeListener = event.listen("readTheme", (e) => {
const theme = <string>e.payload;
if (theme === "dark") {
icon.value = iconLight.value;
@@ -77,9 +77,7 @@ onMounted(async () => {
});
onUnmounted(() => {
if (themeListener) {
themeListener();
}
themeListener();
const urlList = [iconLight.value, iconDark.value, offer.value];
urlList.forEach((url) => {
URL.revokeObjectURL(typeof url === "string" ? url : "");

View File

@@ -91,7 +91,7 @@
</template>
<script lang="ts" setup>
import { event } from "@tauri-apps/api";
import { UnlistenFn } from "@tauri-apps/api/helpers/event";
import { UnlistenFn } from "@tauri-apps/api/event";
import { storeToRefs } from "pinia";
import { computed, onBeforeMount, onMounted, onUnmounted, ref, watch } from "vue";
@@ -136,7 +136,7 @@ onBeforeMount(async () => {
color: "success",
});
}
collectListener = await event.listen("refreshCollect", async () => await load());
collectListener = event.listen("refreshCollect", async () => await load());
});
onMounted(async () => await load());

View File

@@ -1,12 +1,10 @@
/**
* @file plugins/Mys/utils/doGameLogin
* @file plugins/Mys/request/doGameLogin
* @description 获取 gameToken曲线获取 stoken
* @since Beta v0.4.4
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
import { getDeviceInfo } from "../../../utils/toolFunc.js";
import { getRequestHeader } from "../../../web/utils/getRequestHeader.js";
@@ -14,7 +12,7 @@ const APP_ID = 8;
/**
* @description 获取登录二维码
* @since Beta v0.4.4
* @since Beta v0.5.0
* @returns {Promise<TGApp.Plugins.Mys.GameLogin.GetLoginQrData|TGApp.BBS.Response.Base>}
*/
export async function getLoginQr(): Promise<
@@ -24,19 +22,20 @@ export async function getLoginQr(): Promise<
const device = getDeviceInfo("device_id");
const data = { app_id: APP_ID, device };
const header = getRequestHeader({}, "POST", data, "common");
return await http
.fetch(url, { headers: header, method: "POST", body: http.Body.json(data) })
.then(
(res: Response<TGApp.Plugins.Mys.GameLogin.GetLoginQrResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode === 0) return res.data.data;
return <TGApp.BBS.Response.Base>res.data;
},
);
const resp = await TGHttp<
TGApp.Plugins.Mys.GameLogin.GetLoginQrResponse | TGApp.BBS.Response.Base
>(url, {
method: "POST",
headers: header,
body: JSON.stringify(data),
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}
/**
* @description 获取登录状态
* @since Beta v0.4.4
* @since Beta v0.5.0
* @param {string} ticket 二维码 ticket
* @returns {Promise<TGApp.Plugins.Mys.GameLogin.GetLoginStatusData | TGApp.BBS.Response.Base>}
*/
@@ -47,14 +46,13 @@ export async function getLoginStatus(
const device = getDeviceInfo("device_id");
const data = { app_id: APP_ID, device, ticket };
const header = getRequestHeader({}, "POST", data, "common");
return await http
.fetch(url, { headers: header, method: "POST", body: http.Body.json(data) })
.then(
(
res: Response<TGApp.Plugins.Mys.GameLogin.GetLoginStatusResponse | TGApp.BBS.Response.Base>,
) => {
if (res.data.retcode === 0) return res.data.data;
return <TGApp.BBS.Response.Base>res.data;
},
);
const resp = await TGHttp<
TGApp.Plugins.Mys.GameLogin.GetLoginStatusResponse | TGApp.BBS.Response.Base
>(url, {
method: "POST",
headers: header,
body: JSON.stringify(data),
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}

View File

@@ -1,17 +1,15 @@
/**
* @file plugins/Mys/request/getCollectionPosts.ts
* @description Mys 获取合集帖子
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
import MysApi from "../api/index.js";
/**
* @description 获取合集信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @todo invalid request
* @param {number} collectionId 合集 ID
* @returns {Promise<TGApp.Plugins.Mys.Collection.ResponseData>} 合集信息
@@ -20,24 +18,18 @@ export async function getCollectionData(
collectionId: number,
): Promise<TGApp.Plugins.Mys.Collection.ResponseData> {
const url = "https://bbs-api.miyoushe.com/collection/wapi/collection/detail";
const params = {
id: collectionId.toString(),
};
return await http
.fetch(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
})
.then((res: Response<TGApp.Plugins.Mys.Collection.Response>) => {
console.log(res.data);
return res.data.data;
});
const params = { id: collectionId.toString() };
const resp = await TGHttp<TGApp.Plugins.Mys.Collection.Response>(url, {
method: "GET",
query: params,
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
});
return resp.data;
}
/**
* @description 获取合集帖子
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} collectionId 合集 ID
* @returns {Promise<TGApp.Plugins.Mys.Post.FullData[]>}
*/
@@ -46,11 +38,10 @@ export async function getCollectionPosts(
): Promise<TGApp.Plugins.Mys.Collection.Data[]> {
const url = "https://bbs-api.miyoushe.com/post/wapi/getPostFullInCollection";
const params = { collection_id: collectionId };
return await http
.fetch(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
})
.then((res: Response<TGApp.Plugins.Mys.Collection.ResponsePosts>) => res.data.data.posts);
const resp = await TGHttp<TGApp.Plugins.Mys.Collection.ResponsePosts>(url, {
method: "GET",
query: params,
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
});
return resp.data.posts;
}

View File

@@ -1,31 +1,27 @@
/**
* @file plugins/Mys/request/getEmojis.ts
* @description Mys 表情包请求函数集合
* @since Beta v0.3.0
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取表情包列表
* @since Beta v0.3.0
* @since Beta v0.5.0
* @return {Promise<Record<string,string>|TGApp.BBS.Response.Base>}
*/
export async function getEmojis(): Promise<Record<string, string> | TGApp.BBS.Response.Base> {
const url = "https://bbs-api-static.miyoushe.com/misc/api/emoticon_set";
return await http
.fetch(url)
.then((res: Response<TGApp.Plugins.Mys.Emoji.Response | TGApp.BBS.Response.Base>) => {
if (res.data.retcode === 0) {
const emojis: Record<string, string> = {};
res.data.data.list.forEach((series) => {
series.list.forEach((emoji) => {
emojis[emoji.name] = emoji.icon;
});
});
return emojis;
}
return res.data;
const resp = await TGHttp<TGApp.Plugins.Mys.Emoji.Response | TGApp.BBS.Response.Base>(url, {
method: "GET",
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
const emojis: Record<string, string> = {};
resp.data.list.forEach((series) => {
series.list.forEach((emoji) => {
emojis[emoji.name] = emoji.icon;
});
});
return emojis;
}

View File

@@ -1,15 +1,14 @@
/**
* @file plugins/Mys/request/getForumList.ts
* @description Mys 插件特定论坛请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取特定论坛列表
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {number} forumId 特定论坛 ID
* @param {number} type 排序方式: 0-按热度排序1-最新回复2-按时间排序
* @return {Promise<TGApp.Plugins.Mys.Forum.FullData>}
@@ -20,9 +19,11 @@ async function getForumList(
): Promise<TGApp.Plugins.Mys.Forum.FullData> {
const url = "https://bbs-api.miyoushe.com/post/wapi/getForumPostList";
const params = { forum_id: forumId.toString(), sort_type: type.toString() };
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, query: params })
.then((res: Response<TGApp.Plugins.Mys.Forum.Response>) => res.data.data);
const resp = await TGHttp<TGApp.Plugins.Mys.Forum.Response>(url, {
method: "GET",
query: params,
});
return resp.data;
}
export default getForumList;

View File

@@ -4,19 +4,20 @@
* @since Beta v0.4.5
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取卡池信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @return {Promise<TGApp.Plugins.Mys.Gacha.Data[]>}
*/
async function getGachaData(): Promise<TGApp.Plugins.Mys.Gacha.Data[]> {
const url = "https://api-takumi.mihoyo.com/common/blackboard/ys_obc/v1/gacha_pool?app_sn=ys_obc";
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" } })
.then((res: Response<TGApp.Plugins.Mys.Gacha.Response>) => res.data.data.list);
const resp = await TGHttp<TGApp.Plugins.Mys.Gacha.Response>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
return resp.data.list;
}
export default getGachaData;

View File

@@ -1,24 +1,26 @@
/**
* @file plugins/Mys/request/getHomeNavigator.ts
* @description Mys 插件首页导航请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取首页导航列表
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {number} gid GID
* @return {Promise<TGApp.BBS.Navigator.Navigator[]>}
*/
async function getHomeNavigator(gid: number = 2): Promise<TGApp.BBS.Navigator.Navigator[]> {
const url = "https://bbs-api.miyoushe.com/apihub/api/home/new";
const params = { gids: gid.toString() };
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, query: params })
.then((res: Response<TGApp.BBS.Navigator.HomeResponse>) => res.data.data.navigator);
const resp = await TGHttp<TGApp.BBS.Navigator.HomeResponse>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
query: params,
});
return resp.data.navigator;
}
export default getHomeNavigator;

View File

@@ -1,15 +1,14 @@
/**
* @file plugins/Mys/request/getLotteryData.ts
* @description Mys 插件抽奖接口
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取抽奖信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} lotteryId 抽奖 ID
* @return {Promise<TGApp.BBS.Response.Base|TGApp.Plugins.Mys.Lottery.FullData>}
*/
@@ -18,12 +17,13 @@ async function getLotteryData(
): Promise<TGApp.BBS.Response.Base | TGApp.Plugins.Mys.Lottery.FullData> {
const url = "https://bbs-api.miyoushe.com/painter/wapi/lottery/user/show";
const params = { id: lotteryId };
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, query: params })
.then((res: Response<TGApp.BBS.Response.Base | TGApp.Plugins.Mys.Lottery.Response>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data.show_lottery;
});
const resp = await TGHttp<TGApp.BBS.Response.Base | TGApp.Plugins.Mys.Lottery.Response>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.show_lottery;
}
export default getLotteryData;

View File

@@ -1,15 +1,14 @@
/**
* @file plugins/Mys/request/getNewsList.ts
* @description Mys 插件咨讯请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 获取 News 列表
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} gid GID
* @param {string} newsType 咨讯类型: 1 为公告2 为活动3 为咨讯
* @param {number} pageSize 返回数量
@@ -29,9 +28,12 @@ async function getNewsList(
type: newsType,
last_id: lastId.toString(),
};
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, query: params })
.then((res: Response<TGApp.Plugins.Mys.News.Response>) => res.data.data);
const resp = await TGHttp<TGApp.Plugins.Mys.News.Response>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
query: params,
});
return resp.data;
}
export default getNewsList;

View File

@@ -1,11 +1,10 @@
/**
* @file plugins/Mys/request/getPositionData.ts
* @description Mys 插件热点追踪请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 深度优先遍历
@@ -28,14 +27,16 @@ function DfsObc(list: TGApp.Plugins.Mys.Position.ObcItem[]): TGApp.Plugins.Mys.P
/**
* @description 获取热点追踪信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @return {Promise<TGApp.Plugins.Mys.Position.Data[]>}
*/
export async function getPositionData(): Promise<TGApp.Plugins.Mys.Position.Data[]> {
const url =
"https://api-static.mihoyo.com/common/blackboard/ys_obc/v1/home/position?app_sn=ys_obc";
const res = await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" } })
.then((res: Response<TGApp.Plugins.Mys.Position.Response>) => res.data.data.list);
return DfsObc(res);
const resp = await TGHttp<TGApp.Plugins.Mys.Position.Response>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
});
const data = resp.data.list;
return DfsObc(data);
}

View File

@@ -1,32 +1,27 @@
/**
* @file plugins Mys request getPostData.ts
* @description Mys帖子请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
import MysApi from "../api/index.js";
/**
* @description 获取帖子信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {number} postId 帖子 ID
* @return {Promise<TGApp.Plugins.Mys.Post.FullData>}
*/
async function getPostData(postId: number): Promise<TGApp.Plugins.Mys.Post.FullData> {
const url = "https://bbs-api.mihoyo.com/post/wapi/getPostFull";
const params = {
post_id: postId.toString(),
};
return await http
.fetch(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
})
.then((res: Response<TGApp.Plugins.Mys.Post.Response>) => res.data.data.post);
const params = { post_id: postId.toString() };
const resp = await TGHttp<TGApp.Plugins.Mys.Post.Response>(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
});
return resp.data.post;
}
export default getPostData;

View File

@@ -1,17 +1,15 @@
/**
* @file plugins/Mys/request/getVoteData.ts
* @description Mys 插件投票请求
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
import MysApi from "../api/index.js";
/**
* @description 获取投票信息
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} id 投票 ID
* @param {string} uid 用户 ID
* @return {Promise<TGApp.Plugins.Mys.Vote.Info>}
@@ -19,18 +17,17 @@ import MysApi from "../api/index.js";
export async function getVoteInfo(id: string, uid: string): Promise<TGApp.Plugins.Mys.Vote.Info> {
const url = "https://bbs-api.miyoushe.com/apihub/api/getVotes";
const params = { owner_uid: uid, vote_ids: id };
return await http
.fetch(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
})
.then((res: Response<TGApp.Plugins.Mys.Vote.InfoResponse>) => res.data.data.data[0]);
const resp = await TGHttp<TGApp.Plugins.Mys.Vote.InfoResponse>(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
});
return resp.data.data[0];
}
/**
* @description 获取投票结果
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} id 投票 ID
* @param {string} uid 用户 ID
* @return {Promise<TGApp.Plugins.Mys.Vote.Result>}
@@ -41,11 +38,10 @@ export async function getVoteResult(
): Promise<TGApp.Plugins.Mys.Vote.Result> {
const url = "https://bbs-api.miyoushe.com/apihub/api/getVotesResult";
const params = { owner_uid: uid, vote_ids: id };
return await http
.fetch(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
})
.then((res: Response<TGApp.Plugins.Mys.Vote.ResultResponse>) => res.data.data.data[0]);
const resp = await TGHttp<TGApp.Plugins.Mys.Vote.ResultResponse>(url, {
method: "GET",
headers: { "Content-Type": "application/json", Referer: MysApi.PostReferer },
query: params,
});
return resp.data.data[0];
}

View File

@@ -1,15 +1,14 @@
/**
* @file plugins/Mys/request/searchPost.ts
* @description 帖子搜索
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../../utils/TGHttp.js";
/**
* @description 搜索帖子
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {string} gid 游戏分区 ID
* @param {string} keyword 关键词
* @param {string} last_id 最后一条帖子 ID
@@ -22,9 +21,12 @@ async function searchPosts(
): Promise<TGApp.Plugins.Mys.Search.PostsResponseData> {
const url = "https://bbs-api.miyoushe.com/post/wapi/searchPosts";
const params = { gids: gid, keyword, last_id, size: "20" };
return await http
.fetch(url, { method: "GET", headers: { "Content-Type": "application/json" }, query: params })
.then((res: Response<TGApp.Plugins.Mys.Search.PostsResponse>) => res.data.data);
const resp = await TGHttp<TGApp.Plugins.Mys.Search.PostsResponse>(url, {
method: "GET",
headers: { "Content-Type": "application/json" },
query: params,
});
return resp.data;
}
export default searchPosts;

View File

@@ -1,12 +1,12 @@
/**
* @file plugins/Mys/utils/getPositionCard.ts
* @description Mys 插件热点追踪工具
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
/**
* @description 根据热点追踪信息转为渲染用的数据
* @since Beta v0.4.10
* @since Beta v0.5.0
* @param {TGApp.Plugins.Mys.Position.Data[]} positionData 列表
* @returns {TGApp.Plugins.Mys.Position.RenderCard[]} 返回列表
*/

View File

@@ -1,7 +1,7 @@
/**
* @file plugins/Sqlite/utils/transUserRecord.ts
* @description Sqlite 数据转换 用户战绩数据转换模块
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
/**
@@ -79,7 +79,7 @@ function transAvatar(data: TGApp.Game.Record.Avatar[]): string {
/**
* @description 将统计信息转换为数据库中的数据
* @since Beta v0.4.10
* @since Beta v0.5.0
* @param {TGApp.Game.Record.Stats} data 统计信息
* @return {string} 转换后的统计信息
*/

View File

@@ -1,12 +1,12 @@
/**
* @file types/Game/Record.d.ts
* @description 原神战绩相关类型定义文件
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
/**
* @description 原神战绩相关类型定义命名空间
* @since Beta v0.4.10
* @since Beta v0.5.0
* @namespace TGApp.Game.Record
* @memberof TGApp.Game
*/
@@ -47,7 +47,7 @@ declare namespace TGApp.Game.Record {
/**
* @description 角色信息类型
* @interface Role
* @since Beta v0.4.10
* @since Beta v0.5.0
* @property {string} AvatarUrl - 角色头像 // 通常为 ""
* @property {string} nickname - 角色昵称
* @property {string} region - 区域
@@ -95,7 +95,7 @@ declare namespace TGApp.Game.Record {
/**
* @description 统计信息类型
* @interface Stats
* @since Beta v0.4.10
* @since Beta v0.5.0
* @property {number} active_day_number - 活跃天数
* @property {number} achievement_number - 成就数量
* @property {number} anemoculus_number - 风神瞳数量
@@ -140,7 +140,7 @@ declare namespace TGApp.Game.Record {
/**
* @description 幻想真境剧诗数据类型
* @interface CombatStats
* @since Beta v0.4.10
* @since Beta v0.5.0
* @property {boolean} is_unlock - 是否解锁
* @property {number} max_round_id - 最大报幕数
* @property {boolean} has_data - 是否有数据

View File

@@ -1,12 +1,12 @@
/**
* @file types/Sqlite/Record.d.ts
* @description Sqlite 原神战绩相关类型定义文件
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
/**
* @description Sqlite 原神战绩相关类型定义命名空间
* @since Beta v0.4.10
* @since Beta v0.5.0
* @namespace Record
* @memberof TGApp.Sqlite
*/
@@ -78,7 +78,7 @@ declare namespace TGApp.Sqlite.Record {
/**
* @description 统计信息类型
* @interface Stats
* @since Beta v0.4.10
* @since Beta v0.5.0
* @property {number} activeDays - 活跃天数
* @property {number} achievementNumber - 成就达成数
* @property {number} avatarNumber - 获得角色数

View File

@@ -1,13 +1,13 @@
/**
* @file utils/TGClient.ts
* @desc 负责米游社客户端的 callback 处理
* @since Beta v0.4.4
* @since Beta v0.5.0
*/
import { event, invoke } from "@tauri-apps/api";
import { event, core } from "@tauri-apps/api";
import type { Event } from "@tauri-apps/api/event";
import type { UnlistenFn } from "@tauri-apps/api/helpers/event";
import { appWindow, WebviewWindow } from "@tauri-apps/api/window";
import type { UnlistenFn } from "@tauri-apps/api/event";
import { Window } from "@tauri-apps/api/window";
import showSnackbar from "../components/func/snackbar.js";
import TGSqlite from "../plugins/Sqlite/index.js";
@@ -44,11 +44,11 @@ class TGClient {
/**
* @private 窗口实例
* @since Beta v0.3.4
* @type {WebviewWindow}
* @since Beta v0.5.0
* @type {Window}
* @memberof TGClient
*/
private window: WebviewWindow | null;
private window: Window | null;
/**
* @private 模拟路由
@@ -66,7 +66,7 @@ class TGClient {
*/
constructor() {
try {
this.window = WebviewWindow.getByLabel("mhy_client");
this.window = Window.getByLabel("mhy_client");
} catch (error) {
this.window = null;
}
@@ -94,7 +94,7 @@ class TGClient {
/**
* @func callback
* @since Beta v0.4.2
* @since Beta v0.5.0
* @desc 回调函数
* @param {string} callback - 回调函数名
* @param {object} data - 回调数据
@@ -108,7 +108,7 @@ class TGClient {
};
const js = `javascript:mhyWebBridge("${callback}", ${JSON.stringify(response)});`;
console.info(`[callback] ${js}`);
await invoke("execute_js", { label: "mhy_client", js });
await core.invoke("execute_js", { label: "mhy_client", js });
}
/**
@@ -270,13 +270,13 @@ class TGClient {
await this.nullCallback(<TGApp.Plugins.JSBridge.NullArg>argParse);
break;
default:
console.warn(`[${arg.windowLabel}] ${JSON.stringify(argParse)}`);
console.warn(`[${arg.event}] ${JSON.stringify(argParse)}`);
}
}
/**
* @func handleCustomCallback
* @since Beta v0.4.3
* @since Beta v0.5.0
* @desc 处理自定义的 callback
* @param {TGApp.Plugins.JSBridge.Arg<any>} arg - 事件参数
* @returns {Promise<void>} - 返回值
@@ -294,7 +294,7 @@ class TGClient {
const executeJS = `javascript:(function(){
window.location.reload();
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
await this.loadJSBridge();
break;
}
@@ -380,7 +380,7 @@ class TGClient {
};
document.addEventListener("mousedown", mouseDownListener);
})()`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
break;
}
default:
@@ -390,7 +390,7 @@ class TGClient {
/**
* @func hideOverlay
* @since Beta v0.3.7
* @since Beta v0.5.0
* @desc 隐藏遮罩
* @returns {Promise<void>}
*/
@@ -401,12 +401,12 @@ class TGClient {
box.remove();
}
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
}
/**
* @func hideSideBar
* @since Beta v0.3.5
* @since Beta v0.5.0
* @desc 隐藏侧边栏
* @returns {void} - 无返回值
*/
@@ -421,12 +421,12 @@ class TGClient {
document.querySelector('body').appendChild(style);
}
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
}
/**
* @func loadJSBridge
* @since Beta v0.3.8
* @since Beta v0.5.0
* @desc 加载 JSBridge
* @returns {void} - 无返回值
*/
@@ -438,12 +438,12 @@ class TGClient {
closePage: function() { this.postMessage('{"method":"closePage"}') },
};
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
}
/**
* @func loadSignIn
* @since Beta v0.4.4
* @since Beta v0.5.0
* @desc 自动检测登录ck
* @returns {Promise<void>}
*/
@@ -465,7 +465,7 @@ class TGClient {
}
}
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
}
/**
@@ -481,7 +481,7 @@ class TGClient {
/**
* @func open
* @since Beta v0.4.4
* @since Beta v0.5.0
* @desc 打开米游社客户端
* @param {string} func - 方法名
* @param {string} url - url
@@ -491,8 +491,8 @@ class TGClient {
if (url === undefined) url = this.getUrl(func);
this.route = [url];
await TGLogger.Info(`[TGClient][open][${func}] ${url}`);
await invoke<InvokeArg>("create_mhy_client", { func, url });
this.window = WebviewWindow.getByLabel("mhy_client");
await core.invoke<InvokeArg>("create_mhy_client", { func, url });
this.window = Window.getByLabel("mhy_client");
await this.window?.show();
await this.window?.setFocus();
await this.loadJSBridge();
@@ -504,7 +504,7 @@ class TGClient {
/* JSBridge 回调处理 */
/**
* @func closePage
* @since Beta v0.3.9
* @since Beta v0.5.0
* @desc 关闭米游社客户端的页面
* @param {TGApp.Plugins.JSBridge.NullArg} arg - 请求参数
* @returns {void} - 无返回值
@@ -520,7 +520,7 @@ class TGClient {
const executeJS = `javascript:(function(){
window.location.href = '${url}';
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
await this.loadJSBridge();
}
@@ -618,7 +618,7 @@ class TGClient {
/**
* @func getCookieToken
* @since Beta v0.4.0
* @since Beta v0.5.0
* @desc 获取米游社客户端的 cookie_token
* @param {TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.GetCookieTokenPayload>} arg - 请求参数
* @returns {void} - 无返回值
@@ -648,7 +648,7 @@ class TGClient {
document.cookie = "ltmid_v2=${user.cookie.mid};domain=.mihoyo.com;path=/;expires=Fri, 31 Dec 9999 23:59:59 GMT;";
})();`;
console.info(`[getCookieToken] ${executeJS}`);
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
const data = {
cookie_token: user.cookie.cookie_token,
};
@@ -744,7 +744,7 @@ class TGClient {
/**
* @func onClickImg
* @since Beta v0.3.9
* @since Beta v0.5.0
* @desc 点击图片,下载到本地
* @param {TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.OnClickImgPayload>} arg - 方法参数
* @returns {void} - 无返回值
@@ -755,12 +755,12 @@ class TGClient {
const { image_list } = arg.payload;
const image = image_list[0];
const executeJS = this.getSaveImgJS(image.url, image.format);
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
}
/**
* @func openApplication
* @since Beta v0.3.9
* @since Beta v0.5.0
* @desc 打开应用
* @param {TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.OpenApplicationPayload>} arg - 方法参数
* @returns {void} - 无返回值
@@ -769,7 +769,8 @@ class TGClient {
arg: TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.OpenApplicationPayload>,
): Promise<void> {
console.log(`[openApplication] ${JSON.stringify(arg.payload)}`);
await appWindow.setFocus();
const appWindow = Window.getByLabel("TeyvatGuide");
await appWindow?.setFocus();
showSnackbar({
text: `不支持的操作OpenApplication(${JSON.stringify(arg.payload)})`,
color: "error",
@@ -784,7 +785,7 @@ class TGClient {
/**
* @func pushPage
* @since Beta v0.3.9
* @since Beta v0.5.0
* @desc 打开米游社客户端的页面
* @param {TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.PushPagePayload>} arg - 方法参数
* @returns {Promise<void>} - 无返回值
@@ -794,7 +795,8 @@ class TGClient {
): Promise<void> {
const res = await parseLink(arg.payload.page, true);
if (!res) {
await appWindow.setFocus();
const appWindow = Window.getByLabel("TeyvatGuide");
await appWindow?.setFocus();
showSnackbar({
text: `未知链接:${arg.payload.page}`,
color: "error",
@@ -814,7 +816,7 @@ class TGClient {
const executeJS = `javascript:(function(){
window.location.href = '${res}';
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
await this.loadJSBridge();
await this.hideSideBar();
await this.hideOverlay();
@@ -838,7 +840,7 @@ class TGClient {
/**
* @func share
* @since Beta v0.4.4
* @since Beta v0.5.0
* @desc 分享
* @param {TGApp.Plugins.JSBridge.Arg<TGApp.Plugins.JSBridge.SharePayload>} arg - 方法参数
* @returns {Promise<void>} - 无返回值
@@ -849,7 +851,7 @@ class TGClient {
const image = arg.payload.content.image_url;
const format = image.split(".").pop();
const executeJS = this.getSaveImgJS(image, format ?? "png");
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
await this.callback(arg.callback, {});
return;
}
@@ -924,7 +926,7 @@ class TGClient {
}
mhyWebBridge("${arg.callback}", {});
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
return;
}
if (arg.payload.type === "image") {
@@ -952,7 +954,7 @@ class TGClient {
}
mhyWebBridge('${arg.callback}', {});
})();`;
await invoke("execute_js", { label: "mhy_client", js: executeJS });
await core.invoke("execute_js", { label: "mhy_client", js: executeJS });
return;
}
}

62
src/utils/TGHttp.ts Normal file
View File

@@ -0,0 +1,62 @@
/**
* @file utils/TGHttp.ts
* @description 封装HTTP请求
* @since Beta v0.5.0
*/
import { fetch } from "@tauri-apps/plugin-http";
/**
* @description 请求参数
* @since Beta v0.5.0
* @property {"GET"|"POST"} method 请求方法
* @property {Record<string,string>} headers 请求头
* @property {Record<string,string>} query 请求参数
* @property {string} body 请求体
* @return TGHttpParams
*/
type TGHttpParams = {
method: "GET" | "POST";
headers?: Record<string, string>;
query?: Record<string, any>;
body?: string;
};
/**
* @description 发送请求
* @since Beta v0.5.0
* @template T
* @param {string} url 请求地址
* @param {TGHttpParams} options 请求参数
* @returns {Promise<T>}
*/
async function TGHttp<T>(url: string, options: TGHttpParams): Promise<T> {
let httpHeaders = new Headers();
if (options.headers) {
httpHeaders = new Headers(options.headers);
}
const fetchOptions: RequestInit = {
method: options.method,
headers: httpHeaders,
};
if (options.query) {
const query = new URLSearchParams(options.query).toString();
url += `?${query}`;
}
if (options.body) {
fetchOptions.body = options.body;
}
return await fetch(url, fetchOptions)
.then((res) => {
if (res.ok) {
return res.json();
}
throw new Error(`HTTP error! status: ${res.status}`);
})
.catch((err) => {
console.error("HTTP error: ", err);
return err;
});
}
export default TGHttp;

View File

@@ -1,22 +1,24 @@
/**
* @file utils/TGShare.ts
* @description 生成分享截图并保存到本地
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
import { dialog, fs, http, path } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import { path } from "@tauri-apps/api";
import { save } from "@tauri-apps/plugin-dialog";
import { writeFile } from "@tauri-apps/plugin-fs";
import html2canvas from "html2canvas";
import showConfirm from "../components/func/confirm.js";
import showSnackbar from "../components/func/snackbar.js";
import TGHttp from "./TGHttp.js";
import TGLogger from "./TGLogger.js";
import { bytesToSize } from "./toolFunc.js";
/**
* @description 保存图片-canvas
* @since Beta v0.4.10
* @since Beta v0.5.0
* @param {Uint8Array} buffer - 图片数据
* @param {string} filename - 文件名
* @param {string} format - 文件格式
@@ -28,7 +30,7 @@ export async function saveCanvasImg(
format?: string,
): Promise<void> {
if (format === undefined) format = "png";
const res = await dialog.save({
const res = await save({
title: "保存图片",
filters: [{ name: "图片", extensions: [format] }],
defaultPath: `${await path.downloadDir()}${path.sep}${filename}.${format}`,
@@ -37,38 +39,32 @@ export async function saveCanvasImg(
await TGLogger.Info(`[saveCanvasImg][${filename}] 未选择保存路径`);
return;
}
await fs.writeBinaryFile({ path: res, contents: buffer });
await writeFile(res, buffer);
await TGLogger.Info(`[saveCanvasImg][${filename}] 已将图像保存到本地`);
}
/**
* @description 将图片保存到本地
* @since Beta v0.4.10
* @since Beta v0.5.0
* @param {string} url - 图片链接
* @returns {Promise<string>} 图片元素
*/
export async function saveImgLocal(url: string): Promise<string> {
const res: Response<Uint8Array> = await http.fetch(url, {
method: "GET",
responseType: http.ResponseType.Binary,
});
const buffer = new Uint8Array(res.data);
const res = await TGHttp<Uint8Array>(url, { method: "GET" });
const buffer = new Uint8Array(res);
const blob = new Blob([buffer], { type: "image/png" });
return URL.createObjectURL(blob);
}
/**
* @description 返回图片 buffer
* @since Beta v0.4.10
* @since Beta v0.5.0
* @param {string} url - 图片链接
* @returns {Promise<Uint8Array>} 图片 buffer
*/
export async function getImageBuffer(url: string): Promise<Uint8Array> {
const res: Response<Uint8Array> = await http.fetch(url, {
method: "GET",
responseType: http.ResponseType.Binary,
});
return new Uint8Array(res.data);
const res = await TGHttp<Uint8Array>(url, { method: "GET" });
return new Uint8Array(res);
}
/**

View File

@@ -1,18 +1,19 @@
/**
* @file utils/TGWindow.ts
* @description 窗口创建相关工具函数
* @since Beta v0.4.2
* @since Beta v0.5.0
*/
import { invoke, window as TauriWindow } from "@tauri-apps/api";
import { core, window as TauriWindow } from "@tauri-apps/api";
import type { WindowOptions } from "@tauri-apps/api/window";
import TGLogger from "./TGLogger.js";
/**
* @description 创建TG窗口
* @since Beta v0.3.4
* @since Beta v0.5.0
* @see https://github.com/tauri-apps/tauri/issues/5380
* @todo 需要根据 2.0 版本的 Tauri API 进行修改
* @param {string} url 窗口地址
* @param {string} label 窗口标签
* @param {string} title 窗口标题
@@ -38,7 +39,7 @@ export function createTGWindow(
height,
width,
resizable,
url,
// url,
title,
visible,
x: left,
@@ -46,7 +47,8 @@ export function createTGWindow(
};
const isGet = TauriWindow.WebviewWindow.getByLabel(label);
if (isGet === null) {
invoke("create_window", { label, option })
core
.invoke("create_window", { label, option })
.then(() => {
createTGWindow(url, label, title, width, height, resizable, visible);
})
@@ -57,7 +59,8 @@ export function createTGWindow(
isGet
.close()
.then(() => {
invoke("create_window", { label, option })
core
.invoke("create_window", { label, option })
.then(() => {
console.log(`[createTGWindow][${label}] ${title} created.`);
})

View File

@@ -1,11 +1,11 @@
/**
* @file utils/dataBS.ts
* @description 用户数据的备份、恢复、迁移
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
import { fs, path } from "@tauri-apps/api";
import { FileEntry } from "@tauri-apps/api/fs";
import { path } from "@tauri-apps/api";
import { exists, mkdir, writeTextFile, readDir, readTextFile } from "@tauri-apps/plugin-fs";
import showSnackbar from "../components/func/snackbar.js";
import TGSqlite from "../plugins/Sqlite/index.js";
@@ -17,23 +17,23 @@ import { exportUigfData, readUigfData, verifyUigfData } from "./UIGF.js";
/**
* @description 备份用户数据
* @since Beta v0.4.7
* @since Beta v0.5.0
* @param {string} dir 备份目录路径
* @returns {Promise<void>}
*/
export async function backUpUserData(dir: string): Promise<void> {
if (!(await fs.exists(dir))) {
if (!(await exists(dir))) {
console.log("备份目录不存在,创建备份目录");
await fs.createDir(dir, { recursive: true });
await mkdir(dir, { recursive: true });
}
const dataAchi = await TSUserAchi.getUIAF();
await fs.writeTextFile(`${dir}${path.sep}UIAF.json`, JSON.stringify(dataAchi));
await writeTextFile(`${dir}${path.sep}UIAF.json`, JSON.stringify(dataAchi));
// 备份 ck
const dataCK = await TGSqlite.getCookie();
await fs.writeTextFile(`${dir}${path.sep}cookie.json`, JSON.stringify(dataCK));
await writeTextFile(`${dir}${path.sep}cookie.json`, JSON.stringify(dataCK));
// 备份深渊数据
const dataAbyss = await TGSqlite.getAbyss();
await fs.writeTextFile(`${dir}${path.sep}abyss.json`, JSON.stringify(dataAbyss));
await writeTextFile(`${dir}${path.sep}abyss.json`, JSON.stringify(dataAbyss));
// 备份祈愿数据
const uidList = await TSUserGacha.getUidList();
for (const uid of uidList) {
@@ -45,28 +45,28 @@ export async function backUpUserData(dir: string): Promise<void> {
/**
* @description 恢复用户数据
* @since Beta v0.4.7
* @since Beta v0.5.0
* @param {string} dir 备份目录路径
* @returns {Promise<void>}
*/
export async function restoreUserData(dir: string): Promise<void> {
let errNum = 0;
if (!(await fs.exists(dir))) {
if (!(await exists(dir))) {
showSnackbar({
text: "备份目录不存在",
color: "error",
});
return;
}
const filesRead = await fs.readDir(dir, { recursive: false });
const files: FileEntry[] = filesRead.filter((item: FileEntry) => item.path.endsWith(".json"));
const filesRead = await readDir(dir);
const files = filesRead.filter((item) => item.isFile && item.name.endsWith(".json"));
await TGLogger.Info(`[DataBS][restoreUserData] files: ${JSON.stringify(files)}`);
// 恢复成就数据
const achiFind = files.find((item) => item.name === "UIAF.json");
if (achiFind) {
try {
const dataAchi: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(
await fs.readTextFile(achiFind.path),
await readTextFile(achiFind.name),
);
await TSUserAchi.mergeUIAF(dataAchi);
await TGLogger.Info(`[DataBS][restoreUserData] 成就数据恢复成功`);
@@ -90,7 +90,7 @@ export async function restoreUserData(dir: string): Promise<void> {
const ckFind = files.find((item) => item.name === "cookie.json");
if (ckFind) {
try {
const dataCK = await fs.readTextFile(ckFind.path);
const dataCK = await readTextFile(ckFind.name);
await TGSqlite.saveAppData("cookie", JSON.stringify(JSON.parse(dataCK)));
await TGLogger.Info(`[DataBS][restoreUserData] Cookie 数据恢复成功`);
} catch (e) {
@@ -114,7 +114,7 @@ export async function restoreUserData(dir: string): Promise<void> {
if (abyssFind) {
try {
const dataAbyss: TGApp.Sqlite.Abyss.SingleTable[] = JSON.parse(
await fs.readTextFile(abyssFind.path),
await readTextFile(abyssFind.name),
);
await TGSqlite.restoreAbyss(dataAbyss);
} catch (e) {
@@ -134,14 +134,14 @@ export async function restoreUserData(dir: string): Promise<void> {
}
// 恢复祈愿数据
const reg = /UIGF_(\d+).json/;
const dataGachaList = files.filter((item) => reg.test(item.path));
const dataGachaList = files.filter((item) => reg.test(item.name));
for (const item of dataGachaList) {
const check = await verifyUigfData(item.path);
const check = await verifyUigfData(item.name);
if (!check) {
errNum++;
continue;
}
const data = await readUigfData(item.path);
const data = await readUigfData(item.name);
const uid = data.info.uid;
try {
await TSUserGacha.mergeUIGF(uid, data.list);

View File

@@ -1,10 +1,11 @@
/**
* @file utils/toolFunc.ts
* @description 一些工具函数
* @since Beta v0.4.1
* @since Beta v0.5.0
*/
import { os, path } from "@tauri-apps/api";
import { path } from "@tauri-apps/api";
import { type } from "@tauri-apps/plugin-os";
import colorConvert from "color-convert";
import type { KEYWORD } from "color-convert/conversions.js";
import { v4 } from "uuid";
@@ -108,17 +109,18 @@ export function bytesToSize(bytes: number): string {
/**
* @description 获取缓存目录
* @since Beta v0.3.4
* @since Beta v0.5.0
* @returns {string|string[]} 缓存目录
*/
export async function getCacheDir(): Promise<string[] | false> {
const cacheDir = await path.appCacheDir();
const osType = await os.type();
if (osType === "Windows_NT") {
const osType = type().toLowerCase();
if (osType === "windows") {
const cache = `${cacheDir}EBWebview${path.sep}Default${path.sep}Cache`;
const codeCache = `${cacheDir}EBWebview${path.sep}Default${path.sep}Code Cache`;
return [cache, codeCache];
} else if (osType === "Darwin") {
}
if (osType === "macos") {
return [`${cacheDir}WebKit`];
}
return false;

View File

@@ -1,7 +1,7 @@
/**
* @file web/constant/bbs.ts
* @description 常量-应用数据
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
export const BBS_VERSION = "2.72.2";
@@ -12,7 +12,7 @@ export const BBS_APP_ID = "bll8iq97cem8";
/**
* @description salt 值
* @version 2.72.2
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
export const BBS_SALT = {
K2: "KsQAfcXzHdMjoQQqjnPXVTXAygltZbSI",

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/genAuthkey.ts
* @description 生成 authkey
* @since Beta v0.3.7
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGConstant from "../constant/TGConstant.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 生成 authkey
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {Record<string, string>} cookie cookie // stoken_v2 & mid
* @param {string} gameUid 游戏 uid
* @returns {Promise<string|TGApp.BBS.Response.Base>} authkey
@@ -29,17 +27,18 @@ export async function genAuthkey(
region: TGUtils.Tools.getServerByUid(gameUid),
};
const header = TGUtils.User.getHeader(cookie, "POST", JSON.stringify(data), "lk2", true);
return await http
.fetch(url, { method: "POST", headers: header, body: http.Body.json(data) })
.then((res: Response<TGApp.Game.Gacha.AuthkeyResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode === 0) return res.data.data.authkey;
return res.data;
});
const resp = await TGHttp<TGApp.Game.Gacha.AuthkeyResponse | TGApp.BBS.Response.Base>(url, {
method: "POST",
headers: header,
body: JSON.stringify(data),
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.authkey;
}
/**
* @description 生成 authkey
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {Record<string, string>} cookie cookie // stoken_v2 & mid
* @param {object} payload payload
* @returns {Promise<string|TGApp.BBS.Response.Base>} authkey
@@ -50,7 +49,9 @@ export async function genAuthkey2(
): Promise<TGApp.BBS.Response.Base> {
const url = "https://api-takumi.mihoyo.com/binding/api/genAuthKey";
const header = TGUtils.User.getHeader(cookie, "POST", JSON.stringify(payload), "lk2", true);
return await http
.fetch(url, { method: "POST", headers: header, body: http.Body.json(payload) })
.then((res: Response<TGApp.BBS.Response.Base>) => res.data);
return await TGHttp<TGApp.BBS.Response.Base>(url, {
method: "POST",
headers: header,
body: JSON.stringify(payload),
});
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getAbyss.ts
* @description 获取深渊信息
* @since Beta v0.3.0
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 获取深渊信息
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {Record<string, string>} cookie cookie
* @param {string} schedule_type 1: 本期, 2: 上期
* @param {TGApp.Sqlite.Account.Game} account 游戏账号
@@ -27,10 +25,11 @@ export async function getAbyss(
const role_id = account.gameUid;
const params = { role_id, schedule_type, server: account.region };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.Game.Abyss.Response | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data;
});
const resp = await TGHttp<TGApp.Game.Abyss.Response | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}

View File

@@ -1,17 +1,15 @@
/**
* @file web/request/getActionTicket.ts
* @description 获取米游社动态的 ActionTicket
* @since Beta v0.3.4
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 通过 stoken 获取 ActionTicket
* @since Beta v0.3.4
* @since Beta v0.5.0
* @param {string} ActionType 动作类型
* @param {string} SToken stoken
* @param {string} MID 用户 MID
@@ -28,7 +26,9 @@ export async function getActionTicketBySToken(
const params = { action_type: ActionType, stoken: SToken, uid: UID };
const cookie = { mid: MID, stoken: SToken };
const header = TGUtils.User.getHeader(cookie, "GET", params, "k2");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.BBS.Response.getActionTicketBySToken>) => res.data);
return await TGHttp<TGApp.BBS.Response.getActionTicketBySToken>(url, {
method: "GET",
headers: header,
query: params,
});
}

View File

@@ -1,10 +1,10 @@
/**
* @file web/request/getAnnouncement.ts
* @description 获取游戏内公告
* @since Beta v0.4.4
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
export enum AnnoServer {
CN_ISLAND = "cn_gf01",
@@ -48,7 +48,7 @@ function getAnnoParams(
/**
* @description 获取游戏内公告列表
* @since Beta v0.4.3
* @since Beta v0.5.0
* @param {string} region 服务器
* @param {AnnoLang} lang 语言
* @returns {Promise<TGApp.BBS.Announcement.ListData>}
@@ -62,14 +62,16 @@ export async function getAnnoList(
if (region !== AnnoServer.CN_ISLAND && region !== AnnoServer.CN_TREE) {
url = "https://hk4e-api-os.hoyoverse.com/common/hk4e_global/announcement/api/getAnnList";
}
return await http
.fetch(url, { method: "GET", query: params })
.then((res: Response<TGApp.BBS.Announcement.ListResponse>) => res.data.data);
const resp = await TGHttp<TGApp.BBS.Announcement.ListResponse>(url, {
method: "GET",
query: params,
});
return resp.data;
}
/**
* @description 获取游戏内公告内容
* @since Beta v0.4.3
* @since Beta v0.5.0
* @param {number} annId 公告 ID
* @param {AnnoServer} region 服务器
* @param {AnnoLang} lang 语言
@@ -85,10 +87,11 @@ export async function getAnnoContent(
if (region !== AnnoServer.CN_ISLAND && region !== AnnoServer.CN_TREE) {
url = "https://hk4e-api-os.hoyoverse.com/common/hk4e_global/announcement/api/getAnnContent";
}
const annoContents: TGApp.BBS.Announcement.ContentItem[] = await http
.fetch(url, { method: "GET", query: params })
.then((res: Response<TGApp.BBS.Announcement.ContentResponse>) => res.data.data.list);
const annoContent = annoContents.find((item) => item.ann_id === annId);
const annoResp = await TGHttp<TGApp.BBS.Announcement.ContentResponse>(url, {
method: "GET",
query: params,
});
const annoContent = annoResp.data.list.find((item) => item.ann_id === annId);
if (annoContent != null) {
return annoContent;
} else {

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getCookieToken.ts
* @description 获取 Cookie Token 的请求函数
* @since Beta v0.3.0
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 根据 stoken 获取 cookie_token
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {string} Mid 登录用户的 mid
* @param {string} Stoken stoken_v2
* @returns {Promise<string|TGApp.BBS.Response.Base>}
@@ -25,17 +23,21 @@ export async function getCookieTokenBySToken(
const cookie = { mid: Mid, stoken: Stoken };
const params = { stoken: Stoken };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.BBS.Response.getCookieTokenBySToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data.cookie_token;
});
const resp = await TGHttp<TGApp.BBS.Response.getCookieTokenBySToken | TGApp.BBS.Response.Base>(
url,
{
method: "GET",
headers: header,
query: params,
},
);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.cookie_token;
}
/**
* @description 根据 gameToken 获取 cookie_token
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {string} accountId 账号 id
* @param {string} gameToken gameToken
* @returns {Promise<string|TGApp.BBS.Response.Base>}
@@ -46,12 +48,13 @@ export async function getCookieTokenByGameToken(
): Promise<string | TGApp.BBS.Response.Base> {
const url = "https://api-takumi.mihoyo.com/auth/api/getCookieAccountInfoByGameToken";
const data = { account_id: Number(accountId), game_token: gameToken };
return await http
.fetch(url, { method: "POST", body: http.Body.json(data) })
.then(
(res: Response<TGApp.BBS.Response.getCookieTokenByGameToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data.cookie_token;
},
);
const resp = await TGHttp<TGApp.BBS.Response.getCookieTokenByGameToken | TGApp.BBS.Response.Base>(
url,
{
method: "POST",
body: JSON.stringify(data),
},
);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.cookie_token;
}

View File

@@ -1,18 +1,16 @@
/**
* @file src/web/request/getDeviceFp.ts
* @description 获取设备指纹
* @since Beta v0.4.1
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import { getInitDeviceInfo } from "../../utils/toolFunc.js";
import TGConstant from "../constant/TGConstant.js";
/**
* @description 获取设备指纹
* @since Beta v0.4.1
* @since Beta v0.5.0
* @param {TGApp.App.Device.DeviceInfo} Info - 设备信息
* @returns {Promise<string>} 设备指纹
*/
@@ -93,11 +91,19 @@ export async function getDeviceFp(
"x-requested-with": "com.mihoyo.hyperion",
Referer: "https://webstatic.mihoyo.com/",
};
info.device_fp = await http
.fetch(url, { method: "POST", body: http.Body.json(data), headers: header })
.then((res: Response<TGApp.BBS.Response.getDeviceFp>) => {
if (res.data.data.code === 200) return res.data.data.device_fp;
return "0000000000000";
try {
const resp = await TGHttp<TGApp.BBS.Response.getDeviceFp>(url, {
method: "POST",
body: JSON.stringify(data),
headers: header,
});
if (resp.retcode !== 0) {
info.device_fp = "0000000000000";
} else {
info.device_fp = resp.data.device_fp;
}
} catch (error) {
info.device_fp = "0000000000000";
}
return info;
}

View File

@@ -1,15 +1,14 @@
/**
* @file web/request/getGachaLog.ts
* @description 获取抽卡记录请求函数
* @since Beta v0.3.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
/**
* @description 获取抽卡记录
* @since Beta v0.3.5
* @since Beta v0.5.0
* @param {string} authkey authkey
* @param {string} gachaType 抽卡类型
* @param {string} endId 结束 id默认为 0
@@ -31,10 +30,10 @@ export async function getGachaLog(
size: "20",
end_id: endId,
};
return await http
.fetch(url, { method: "GET", query: params })
.then((res: Response<TGApp.Game.Gacha.GachaLogResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data.list;
});
const resp = await TGHttp<TGApp.Game.Gacha.GachaLogResponse | TGApp.BBS.Response.Base>(url, {
method: "GET",
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.list;
}

View File

@@ -1,12 +1,10 @@
/**
* @file web/request/getGameAccounts.ts
* @description 获取游戏账号信息相关请求函数
* @since Beta v0.4.3
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGConstant from "../constant/TGConstant.js";
import TGUtils from "../utils/TGUtils.js";
@@ -47,7 +45,7 @@ export async function getGameAccountsByCookie(
/**
* @description 获取游戏账号信息
* @since Alpha v0.2.0
* @since Beta v0.5.0
* @param {string} url 请求地址
* @param {Record<string, string>} cookie cookie
* @param {Record<string, string>} params 请求参数
@@ -59,10 +57,11 @@ async function getGameAccounts(
params: Record<string, string>,
): Promise<TGApp.BBS.Response.Base | TGApp.User.Account.Game[]> {
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.User.Account.GameResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data.list;
});
const resp = await TGHttp<TGApp.User.Account.GameResponse | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.list;
}

View File

@@ -1,18 +1,16 @@
/**
* @file core/utils/getGameRecord.ts
* @description 获取游戏数据的函数
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 获取用户游戏数据
* @since Beta v0.4.10
* @since Beta v0.5.0
* @description 这边的 ck 可以是 cookie_token 和 account_id
* @description 也可以是 ltoken 和 ltuid
* @param {Record<string, string>} cookie cookie
@@ -26,12 +24,11 @@ export async function getGameRecord(
const url = TGApi.GameData.getUserBase;
const params = { role_id: user.gameUid, server: user.region };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.Game.Record.Response | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) {
return <TGApp.BBS.Response.Base>res.data;
}
return res.data.data;
});
const resp = await TGHttp<TGApp.Game.Record.Response | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getLToken.ts
* @description 获取 ltoken 的请求
* @since Beta v0.3.0
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 根据 stoken_v2 获取 ltoken
* @since Beta v0.3.0
* @since Beta v0.5.0
* @param {string} Mid 登录用户 mid
* @param {string} Stoken stoken_v2
* @returns {Promise<string|TGApp.BBS.Response.Base>}
@@ -25,10 +23,11 @@ export async function getLTokenBySToken(
const cookie = { mid: Mid, stoken: Stoken };
const params = { stoken: Stoken };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.BBS.Response.getLTokenBySToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data.ltoken;
});
const resp = await TGHttp<TGApp.BBS.Response.getLTokenBySToken | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.ltoken;
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getRoleList.ts
* @description 获取游戏角色列表的请求方法
* @since Beta v0.3.8
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 通过 Cookie 获取用户角色列表
* @since Beta v0.3.8
* @since Beta v0.5.0
* @param {Record<string, string>} cookie Cookie
* @param {TGApp.Sqlite.Account.Game} account 游戏账号
* @returns {Promise<TGApp.Game.Character.ListItem[]|TGApp.BBS.Response.Base>} 用户角色列表
@@ -23,13 +21,13 @@ export async function getGameRoleListByLToken(
): Promise<TGApp.Game.Character.ListItem[] | TGApp.BBS.Response.Base> {
const url = TGApi.GameData.byCookie.getCharacter;
const uid = account.gameUid;
const data = { role_id: uid, server: TGUtils.Tools.getServerByUid(uid) };
const header = TGUtils.User.getHeader(cookie, "POST", JSON.stringify(data), "common");
return await http
.fetch(url, { method: "POST", headers: header, body: http.Body.json(data) })
.then((res: Response<TGApp.Game.Character.ListResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data.avatars;
});
const resp = await TGHttp<TGApp.Game.Character.ListResponse | TGApp.BBS.Response.Base>(url, {
method: "POST",
headers: header,
body: JSON.stringify(data),
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.avatars;
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getStoken.ts
* @description 获取 stoken
* @since Beta v0.4.4
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGConstant from "../constant/TGConstant.js";
import { getRequestHeader } from "../utils/getRequestHeader.js";
/**
* @description 获取 stoken
* @since Beta v0.4.4
* @since Beta v0.5.0
* @param {string} accountId 账户 ID
* @param {string} token 游戏 Token
* @param {string} isGameToken 是否为游戏 Token
@@ -29,17 +27,17 @@ export async function getStokenByGameToken(
}
const data = { account_id: Number(accountId), game_token: token };
const header = { "x-rpc-app_id": TGConstant.BBS.APP_ID };
return await http
.fetch(url, { method: "POST", headers: header, body: http.Body.json(data) })
.then((res: Response<TGApp.BBS.Response.getStokenByGameToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data;
});
const resp = await TGHttp<TGApp.BBS.Response.getStokenByGameToken | TGApp.BBS.Response.Base>(
url,
{ method: "POST", headers: header, body: JSON.stringify(data) },
);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}
/**
* @description stoken v1 到 v2
* @since Beta v0.4.3
* @since Beta v0.5.0
* @param {string} stoken 账户 ID
* @param {string} stuid 游戏 Token
* @returns {Promise<TGApp.BBS.Response.getStokenByGameTokenData | TGApp.BBS.Response.Base>}
@@ -54,10 +52,10 @@ export async function getTokenBySToken(
"x-rpc-app_id": TGConstant.BBS.APP_ID,
...getRequestHeader(cookie, "POST", "", "prod"),
};
return await http
.fetch(url, { method: "POST", headers: header })
.then((res: Response<TGApp.BBS.Response.getTokenBySToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data;
});
const resp = await TGHttp<TGApp.BBS.Response.getTokenBySToken | TGApp.BBS.Response.Base>(url, {
method: "POST",
headers: header,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}

View File

@@ -1,18 +1,18 @@
/**
* @file web/request/getSyncAvatarDetail.ts
* @description 获取同步角色详情相关请求函数
* @since Beta v0.3.8
* @since Beta v0.5.0
*/
import { app, http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import { app } from "@tauri-apps/api";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 获取同步角色详情
* @since Beta v0.3.8
* @since Beta v0.5.0
* @param {string} accountId 账号 id
* @param {string} cookieToken cookie token
* @param {string} uid 用户 uid
@@ -37,14 +37,15 @@ async function getSyncAvatarDetail(
Referer: "https://webstatic.mihoyo.com/",
Cookie: TGUtils.Tools.transCookie({ account_id: accountId, cookie_token: cookieToken }),
};
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then(
(res: Response<TGApp.Game.Calculate.SyncAvatarDetailResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data;
},
);
const resp = await TGHttp<
TGApp.Game.Calculate.SyncAvatarDetailResponse | TGApp.BBS.Response.Base
>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}
export default getSyncAvatarDetail;

View File

@@ -1,18 +1,18 @@
/**
* @file web/request/getSyncAvatarListAll.ts
* @description 获取同步角色列表请求
* @since Beta v0.3.4
* @since Beta v0.5.0
*/
import { app, http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import { app } from "@tauri-apps/api";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 获取同步角色列表请求
* @since Beta v0.3.4
* @since Beta v0.5.0
* @param {Record<string,string>} cookie cookie
* @param {string} uid 用户 uid
* @param {number} page 页码
@@ -31,14 +31,12 @@ async function getSyncAvatarList(
Referer: "https://webstatic.mihoyo.com/",
Cookie: TGUtils.Tools.transCookie(cookie),
};
return await http
.fetch(url, { method: "POST", body: http.Body.json(data), headers: header })
.then(
(res: Response<TGApp.Game.Calculate.SyncAvatarListResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data.list;
},
);
const resp = await TGHttp<TGApp.Game.Calculate.SyncAvatarListResponse | TGApp.BBS.Response.Base>(
url,
{ method: "POST", body: JSON.stringify(data), headers: header },
);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.list;
}
/**

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getTokens.ts
* @description 获取游戏 Token
* @since Beta v0.4.3
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 根据 login_ticket 获取游戏 Token包括 sToken 和 lToken
* @since Beta v0.4.3
* @since Beta v0.5.0
* @param {string} ticket 登录票证
* @param {string} uid 登录用户 uid
* @returns {Promise<TGApp.BBS.Response.getTokensRes[] | TGApp.BBS.Response.Base>}
@@ -25,11 +23,12 @@ export async function getTokensByLoginTicket(
const url = TGApi.GameTokens.getTokens;
const params = { login_ticket: ticket, token_types: "3", uid };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.BBS.Response.getTokens | TGApp.BBS.Response.Base>) => {
console.log(res);
if (res.data.retcode !== 0) return res.data;
return res.data.data.list;
});
const resp = await TGHttp<TGApp.BBS.Response.getTokens | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
console.log(resp);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.list;
}

View File

@@ -1,17 +1,15 @@
/**
* @file web/request/getUserCollect.ts
* @description 获取用户收藏请求模块
* @since Beta v0.4.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 获取用户收藏帖子
* @since Beta v0.4.5
* @since Beta v0.5.0
* @param {Record<string, string>} cookie - 用户 cookie
* @param {string} uid - 用户 uid
* @param {string} offset - 偏移量
@@ -25,10 +23,11 @@ export async function getUserCollect(
const url = "https://bbs-api.miyoushe.com/post/wapi/userFavouritePost";
const params = { size: "20", uid, offset };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.BBS.Collection.PostResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data;
});
const resp = await TGHttp<TGApp.BBS.Collection.PostResponse | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data;
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/getUserInfo.ts
* @description 获取用户信息请求
* @since Beta v0.3.4
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 根据 cookie 获取用户信息
* @since Beta v0.3.4
* @since Beta v0.5.0
* @param {string} cookie_token cookie token
* @param {string} account_id 用户 account_id
* @returns {Promise<TGApp.BBS.Response.Base | TGApp.Plugins.Mys.User.Info>}
@@ -28,10 +26,11 @@ export async function getUserInfoByCookie(
const url = TGApi.GameData.byCookie.getUserInfo;
const params = { gids: "2" };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common", true);
return await http
.fetch(url, { method: "GET", headers: header, query: params })
.then((res: Response<TGApp.Plugins.Mys.User.HomeResponse | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data.user_info;
});
const resp = await TGHttp<TGApp.Plugins.Mys.User.HomeResponse | TGApp.BBS.Response.Base>(url, {
method: "GET",
headers: header,
query: params,
});
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.user_info;
}

View File

@@ -1,18 +1,16 @@
/**
* @file web/request/verifyLToken.ts
* @description 验证 stoken 的请求函数
* @since Alpha v0.1.5
* @since Beta v0.5.0
*/
import { http } from "@tauri-apps/api";
import type { Response } from "@tauri-apps/api/http";
import TGHttp from "../../utils/TGHttp.js";
import TGApi from "../api/TGApi.js";
import TGUtils from "../utils/TGUtils.js";
/**
* @description 验证 ltoken 有效性,返回 mid
* @since Alpha v0.1.5
* @since Beta v0.5.0
* @param {string} ltoken ltoken
* @param {string} ltuid 登录用户 uid
* @returns {Promise<string | TGApp.BBS.Response.Base>}
@@ -25,10 +23,14 @@ export async function verifyLToken(
const cookie = { ltoken, ltuid };
const data = { ltoken };
const header = TGUtils.User.getHeader(cookie, "POST", data, "common");
return await http
.fetch(url, { method: "POST", headers: header, body: http.Body.json(data) })
.then((res: Response<TGApp.BBS.Response.verifyUserInfoBySToken | TGApp.BBS.Response.Base>) => {
if (res.data.retcode !== 0) return <TGApp.BBS.Response.Base>res.data;
return res.data.data.user_info.mid;
});
const resp = await TGHttp<TGApp.BBS.Response.verifyUserInfoBySToken | TGApp.BBS.Response.Base>(
url,
{
method: "POST",
headers: header,
body: JSON.stringify(data),
},
);
if (resp.retcode !== 0) return <TGApp.BBS.Response.Base>resp;
return resp.data.user_info.mid;
}

View File

@@ -1,7 +1,7 @@
/**
* @file vite.config.ts
* @description vite 配置文件
* @since Beta v0.4.10
* @since Beta v0.5.0
*/
import vue from "@vitejs/plugin-vue";