From 8073d79856dd1732040b003bef45150c7851e801 Mon Sep 17 00:00:00 2001 From: BTMuli Date: Mon, 28 Aug 2023 10:40:20 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=B1=20UIGF=20=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=A4=84=E7=90=86=E8=8D=89=E5=88=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/Sqlite/index.ts | 38 ++++++++++- src/plugins/Sqlite/sql/createTable.sql | 22 +++++- src/plugins/Sqlite/sql/updateData.ts | 43 +++++++++++- src/utils/UIAF.ts | 25 +------ src/utils/UIGF.ts | 92 ++++++++++++++++++++++++++ src/utils/t2D.ts | 23 +++++++ 6 files changed, 212 insertions(+), 31 deletions(-) create mode 100644 src/utils/UIGF.ts create mode 100644 src/utils/t2D.ts diff --git a/src/plugins/Sqlite/index.ts b/src/plugins/Sqlite/index.ts index a4c980e0..7bc5f5df 100644 --- a/src/plugins/Sqlite/index.ts +++ b/src/plugins/Sqlite/index.ts @@ -2,7 +2,7 @@ * @file plugins Sqlite index.ts * @description Sqlite 数据库操作类 * @author BTMuli - * @since Alpha v0.2.2 + * @since Alpha v0.2.3 */ // tauri @@ -10,7 +10,7 @@ import Database from "tauri-plugin-sql-api"; // utils import initDataSql from "./sql/initData"; import initTableSql from "./sql/initTable"; -import { importUIAFData } from "./sql/updateData"; +import { importUIAFData, importUIGFData } from "./sql/updateData"; import { getUiafStatus } from "../../utils/UIAF"; import { insertAbyssData, @@ -30,7 +30,7 @@ class Sqlite { private readonly dbPath: string = "sqlite:tauri-genshin.db"; /** * @description 数据库包含的表 - * @since Alpha v0.2.0 + * @since Alpha v0.2.3 * @private */ private readonly tables: string[] = [ @@ -43,6 +43,7 @@ class Sqlite { "SpiralAbyss", "UserCharacters", "UserRecord", + "GachaRecords", ]; /** @@ -468,6 +469,37 @@ class Sqlite { if (res.length === 0) return false; return res; } + + /** + * @description 获取指定 uid 的用户角色数据 + * @since Alpha v0.2。3 + * @param {string} uid 用户 uid + * @returns {Promise} + */ + public async getGachaRecords(uid: string): Promise { + const db = await Database.load(this.dbPath); + const sql = `SELECT * FROM GachaRecords WHERE uid = '${uid}'`; + const res: TGApp.Sqlite.GachaRecords.SingleTable[] = await db.select(sql); + await db.close(); + return res; + } + + /** + * @description 合并祈愿数据 + * @since Alpha v0.2.3 + * @param {string} uid UID + * @param {string} data UIGF 数据 + * @returns {Promise} + */ + public async mergeUIGF(uid: string, data: string): Promise { + const db = await Database.load(this.dbPath); + const gachaList: TGApp.Plugins.UIGF.GachaItem[] = JSON.parse(data); + const sql = importUIGFData(uid, gachaList); + for (const item of sql) { + await db.execute(item); + } + await db.close(); + } } const TGSqlite = new Sqlite(); diff --git a/src/plugins/Sqlite/sql/createTable.sql b/src/plugins/Sqlite/sql/createTable.sql index 83c1001e..a0d5b634 100644 --- a/src/plugins/Sqlite/sql/createTable.sql +++ b/src/plugins/Sqlite/sql/createTable.sql @@ -1,7 +1,7 @@ -- @file plugins Sqlite sql createTable.sql -- @brief sqlite数据库创建表语句 -- @author BTMuli --- @since Alpha v0.2.0 +-- @since Alpha v0.2.3 -- @brief 创建成就数据表 create table if not exists Achievements @@ -131,7 +131,23 @@ create table if not exists UserCharacters constellation text, activeConstellation integer, costume text, - talent text, -- todo: 数据获取 + talent text, updated text, primary key (uid, cid) -); \ No newline at end of file +); + +-- @brief 创建祈愿数据表 +create table if not exists GachaRecords +( + id text primary key not null, + uid text, + gachaType text, + uigfType text, + time text, + itemId text, + name text, + type text, + rank text, + count text, + updated text +); diff --git a/src/plugins/Sqlite/sql/updateData.ts b/src/plugins/Sqlite/sql/updateData.ts index d84a0f1b..7cf8b20d 100644 --- a/src/plugins/Sqlite/sql/updateData.ts +++ b/src/plugins/Sqlite/sql/updateData.ts @@ -5,9 +5,12 @@ * @since Alpha v0.2.0 */ +// utils +import minifySql from "../../../utils/minifySql"; + /** * @description 导入UIAF数据 - * @since Alpha v0.1.5 + * @since Alpha v0.2.3 * @param {TGApp.Plugins.UIAF.Achievement[]} data * @returns {string[]} sql */ @@ -34,7 +37,43 @@ export function importUIAFData(data: TGApp.Plugins.UIAF.Achievement[]): string[] WHERE id = ${achievement.id} AND progress != ${achievement.current}; `; } - return sqlRes.push(sql); + return sqlRes.push(minifySql(sql)); + }); + return sqlRes; +} + +/** + * @description 导入UIGF数据 + * @since Alpha v0.2.3 + * @param {string} uid - UID + * @param {TGApp.Plugins.UIGF.GachaItem[]} data - UIGF数据 + * @returns {string[]} sql + */ +export function importUIGFData(uid: string, data: TGApp.Plugins.UIGF.GachaItem[]): string[] { + const sqlRes: string[] = []; + data.forEach((gacha) => { + const sql = ` + INSERT INTO GachaRecords (uid, gachaType, itemId, count, time, name, type, rank, id, uigfType, updated) + VALUES ('${uid}', '${gacha.gacha_type}', '${gacha.item_id ?? null}', '${ + gacha.count ?? null + }', '${gacha.time}', + '${gacha.name}', '${gacha.item_type ?? null}', '${gacha.rank_type ?? null}', '${ + gacha.id + }', + '${gacha.uigf_gacha_type}', datetime('now', 'localtime')) + ON CONFLICT (id) DO UPDATE SET + uid = '${uid}', + gachaType = '${gacha.gacha_type}', + uigfType = '${gacha.uigf_gacha_type}', + time = '${gacha.time}', + itemId = '${gacha.item_id ?? null}', + count = '${gacha.count ?? null}', + name = '${gacha.name}', + type = '${gacha.item_type ?? null}', + rank = '${gacha.rank_type ?? null}', + updated = datetime('now', 'localtime'); + `; + sqlRes.push(minifySql(sql)); }); return sqlRes; } diff --git a/src/utils/UIAF.ts b/src/utils/UIAF.ts index 3db0cdf6..c2289209 100644 --- a/src/utils/UIAF.ts +++ b/src/utils/UIAF.ts @@ -1,8 +1,8 @@ /** * @file utils UIAF.ts * @description UIAF工具类 - * @author BTMuli - * @since Alpha v0.1.4 + * @author BTMuli + * @since Alpha v0.2.3 */ // tauri @@ -10,23 +10,6 @@ import { app, fs, path } from "@tauri-apps/api"; // utils import TGSqlite from "../plugins/Sqlite"; -/** - * @description 时间戳转换为日期 - * @since Alpha v0.1.4 - * @param {number} timestamp - 时间戳 - * @returns {string} 日期 2021-01-01 00:00:00 - */ -export function timestampToDate(timestamp: number): string { - return new Date(timestamp * 1000).toLocaleString("zh", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - }); -} - /** * @description 根据 completed 跟 progress 获取 status * @since Alpha v0.1.4 @@ -53,13 +36,9 @@ export function getUiafStatus(completed: boolean, progress: number): number { */ export async function getUiafHeader(): Promise { return { - // eslint-disable-next-line camelcase export_app: "Tauri.Genshin", - // eslint-disable-next-line camelcase export_timestamp: Math.floor(Date.now() / 1000), - // eslint-disable-next-line camelcase export_app_version: await app.getVersion(), - // eslint-disable-next-line camelcase uiaf_version: "v1.1", }; } diff --git a/src/utils/UIGF.ts b/src/utils/UIGF.ts new file mode 100644 index 00000000..51317f8b --- /dev/null +++ b/src/utils/UIGF.ts @@ -0,0 +1,92 @@ +/** + * @file utils UIGF.ts + * @description UIGF工具类 + * @author BTMuli + * @since Alpha v0.2.3 + */ + +// tauri +import { app, fs, path } from "@tauri-apps/api"; +// utils +import TGSqlite from "../plugins/Sqlite"; +import { timestampToDate } from "./t2D"; + +/** + * @description 获取 UIGF 头部信息 + * @since Alpha v0.2.3 + * @param {string} uid - UID + * @returns {Promise} + */ +export async function getUigfHeader(uid: string): Promise { + const stamp = Date.now(); + return { + uid, + lang: "zh-cn", + uigf_version: "2.3.0", + export_timestamp: Math.floor(stamp / 1000), + export_time: timestampToDate(stamp), + export_app: "Tauri.Genshin", + export_app_version: await app.getVersion(), + }; +} + +/** + * @description 检测是否存在 UIGF 数据 + * @description 粗略检测,不保证数据完整性 + * @since Alpha v0.2.3 + * @param {string} path - UIGF 数据路径 + * @returns {Promise} 是否存在 UIGF 数据 + */ +export async function verifyUigfData(path: string): Promise { + const fileData: string = await fs.readTextFile(path); + const UigfData: TGApp.Plugins.UIGF.Export = JSON.parse(fileData).info; + return UigfData.uigf_version !== undefined; +} + +/** + * @description 读取 UIGF 数据 + * @since Alpha v0.2.3 + * @param {string} userPath - UIGF 数据路径 + * @returns {Promise} UIGF 数据 + */ +export async function readUigfData(userPath: string): Promise { + if (await fs.exists(userPath)) { + const fileData = await fs.readTextFile(userPath); + if (fileData !== undefined && fileData !== null && fileData !== "" && fileData !== "{}") { + return fileData; + } else { + return false; + } + } else { + return false; + } +} + +/** + * @description 备份 UIGF 数据 + * @since Alpha v0.2.3 + * @param {TGApp.Plugins.UIAF.GachaItem[]} gachaList - 祈愿列表 + * @param {string} uid - UID + * @returns {Promise} + */ +export async function backupUigfData( + gachaList: TGApp.Plugins.UIGF.GachaItem[], + uid: string, +): Promise { + const savePath = `${await path.appLocalDataDir()}\\userData\\UIGF_${uid}.json`; + await fs.writeTextFile(savePath, JSON.stringify(gachaList, null, 2)); +} + +/** + * @description 恢复 UIGF 数据 + * @since Alpha v0.2.3 + * @param {string} uid - UID + * @returns {Promise} UIGF 数据 + */ +export async function restoreUigfData(uid: string): Promise { + const uigfPath = `${await path.appLocalDataDir()}\\userData\\UIGF_${uid}.json`; + const uigfData = await readUigfData(uigfPath); + if (uigfData === false) return false; + await TGSqlite.mergeUIGF(uid, uigfData); + return true; +} diff --git a/src/utils/t2D.ts b/src/utils/t2D.ts new file mode 100644 index 00000000..820b29d8 --- /dev/null +++ b/src/utils/t2D.ts @@ -0,0 +1,23 @@ +/** + * @file utils t2D.ts + * @description time to date 时间戳转换为日期工具类 + * @author BTMuli + * @since Alpha v0.2.3 + */ + +/** + * @description 时间戳转换为日期 + * @since Alpha v0.2.3 + * @param {number} timestamp - 时间戳(毫秒) + * @returns {string} 日期 2021-01-01 00:00:00 + */ +export function timestampToDate(timestamp: number): string { + return new Date(timestamp).toLocaleString("zh", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + }); +}