diff --git a/src/Starward.Core/EnumExtension.cs b/src/Starward.Core/EnumExtension.cs index 764f864f2..63a8caa92 100644 --- a/src/Starward.Core/EnumExtension.cs +++ b/src/Starward.Core/EnumExtension.cs @@ -271,7 +271,7 @@ public static string ToLocalization(this StarRailQueryType starRailQueryType) - public static string ToLocalization(this ZZZQueryType zZZQueryType) + public static string ToLocalization(this ZZZQueryType zZZQueryType) { return zZZQueryType switch { diff --git a/src/Starward.Core/GameRecord/GameRecordClient.cs b/src/Starward.Core/GameRecord/GameRecordClient.cs index 30bd931f1..86a77b184 100644 --- a/src/Starward.Core/GameRecord/GameRecordClient.cs +++ b/src/Starward.Core/GameRecord/GameRecordClient.cs @@ -8,6 +8,8 @@ using System.Net; using System.Security.Cryptography; using System.Text; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; + #if !DEBUG using System.Net.Http.Json; #endif @@ -274,6 +276,17 @@ protected virtual async Task CommonSendAsync(HttpRequestMessage request, Cancell public abstract Task GetTravelsDiaryDetailAsync(GameRecordRole role, int month, int type, int limit = 100, CancellationToken cancellationToken = default); + + /// + /// 幻想真境剧诗 + /// + /// + /// + /// + public abstract Task> GetImaginariumTheaterInfosAsync(GameRecordRole role, CancellationToken cancellationToken = default); + + + #endregion @@ -375,5 +388,8 @@ protected virtual async Task CommonSendAsync(HttpRequestMessage request, Cancell // 黄金与机械 // https://api-takumi-record.mihoyo.com/game_record/app/hkrpg/api/rogue_nous?server=prod_gf_cn&role_id={uid}&need_detail=true + // 幻想真境剧诗 + // https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/role_combat?server=cn_gf01&role_id={uid}&active=1&need_detail=true + } diff --git a/src/Starward.Core/GameRecord/GameRecordJsonContext.cs b/src/Starward.Core/GameRecord/GameRecordJsonContext.cs index 8643bf019..86714bbd5 100644 --- a/src/Starward.Core/GameRecord/GameRecordJsonContext.cs +++ b/src/Starward.Core/GameRecord/GameRecordJsonContext.cs @@ -1,4 +1,5 @@ -using Starward.Core.GameRecord.Genshin.SpiralAbyss; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; +using Starward.Core.GameRecord.Genshin.SpiralAbyss; using Starward.Core.GameRecord.Genshin.TravelersDiary; using Starward.Core.GameRecord.StarRail.ApocalypticShadow; using Starward.Core.GameRecord.StarRail.ForgottenHall; @@ -24,6 +25,7 @@ namespace Starward.Core.GameRecord; [JsonSerializable(typeof(miHoYoApiWrapper))] [JsonSerializable(typeof(miHoYoApiWrapper))] [JsonSerializable(typeof(miHoYoApiWrapper))] +[JsonSerializable(typeof(miHoYoApiWrapper))] internal partial class GameRecordJsonContext : JsonSerializerContext { diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterAvatar.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterAvatar.cs new file mode 100644 index 000000000..972aea21f --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterAvatar.cs @@ -0,0 +1,42 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterAvatar +{ + + [JsonPropertyName("avatar_id")] + public int AvatarId { get; set; } + + /// + /// 1 自己角色,2 试用角色,3 助演角色 + /// + [JsonPropertyName("avatar_type")] + public int AvatarType { get; set; } + + + [JsonPropertyName("name")] + public string Name { get; set; } + + + [JsonPropertyName("element")] + public string Element { get; set; } + + + [JsonPropertyName("image")] + public string Image { get; set; } + + + [JsonPropertyName("level")] + public int Level { get; set; } + + + [JsonPropertyName("rarity")] + public int Rarity { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterBuff.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterBuff.cs new file mode 100644 index 000000000..937589b8d --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterBuff.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterBuff +{ + + [JsonPropertyName("icon")] + public string Icon { get; set; } + + + [JsonPropertyName("name")] + public string Name { get; set; } + + + [JsonPropertyName("desc")] + public string Desc { get; set; } + + /// + /// 已强化 + /// + [JsonPropertyName("is_enhanced")] + public bool IsEnhanced { get; set; } + + + [JsonPropertyName("id")] + public int Id { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterDetail.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterDetail.cs new file mode 100644 index 000000000..3b5bbdc04 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterDetail.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterDetail +{ + + [JsonPropertyName("rounds_data")] + public List RoundsData { get; set; } + + /// + /// 数据不全,完整数据参考 + /// + [JsonPropertyName("detail_stat")] + public ImaginariumTheaterStat DetailStat { get; set; } + + + [JsonPropertyName("lineup_link")] + public string LineupLink { get; set; } + + /// + /// 待命角色 + /// + [JsonPropertyName("backup_avatars")] + public List BackupAvatars { get; set; } + + + [JsonPropertyName("fight_statisic")] + public ImaginariumTheaterFightStatisic FightStatisic { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterEnemy.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterEnemy.cs new file mode 100644 index 000000000..2b60b09ab --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterEnemy.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterEnemy +{ + + [JsonPropertyName("name")] + public string Name { get; set; } + + + [JsonPropertyName("icon")] + public string Icon { get; set; } + + + [JsonPropertyName("level")] + public int Level { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisic.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisic.cs new file mode 100644 index 000000000..8b19302b3 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisic.cs @@ -0,0 +1,53 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterFightStatisic +{ + + /// + /// 击败最多敌人 + /// + [JsonPropertyName("max_defeat_avatar")] + public ImaginariumTheaterFightStatisicAvatar MaxDefeatAvatar { get; set; } + + /// + /// 最高伤害输出 + /// + [JsonPropertyName("max_damage_avatar")] + public ImaginariumTheaterFightStatisicAvatar MaxDamageAvatar { get; set; } + + /// + /// 最高承受伤害 + /// + [JsonPropertyName("max_take_damage_avatar")] + public ImaginariumTheaterFightStatisicAvatar MaxTakeDamageAvatar { get; set; } + + /// + /// 本次消耗幻剧之花 + /// + [JsonPropertyName("total_coin_consumed")] + public ImaginariumTheaterFightStatisicAvatar TotalCoinConsumed { get; set; } + + /// + /// 最快完成演出的队伍 + /// + [JsonPropertyName("shortest_avatar_list")] + public List ShortestAvatarList { get; set; } + + /// + /// 演出总时长(秒) + /// + [JsonPropertyName("total_use_time")] + public int TotalUseTime { get; set; } + + + [JsonPropertyName("is_show_battle_stats")] + public bool IsShowBattleStats { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisicAvatar.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisicAvatar.cs new file mode 100644 index 000000000..abd78a6a0 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterFightStatisicAvatar.cs @@ -0,0 +1,28 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterFightStatisicAvatar +{ + + [JsonPropertyName("avatar_id")] + public int AvatarId { get; set; } + + + [JsonPropertyName("avatar_icon")] + public string AvatarIcon { get; set; } + + + [JsonPropertyName("value")] + public string Value { get; set; } + + + [JsonPropertyName("rarity")] + public int Rarity { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterInfo.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterInfo.cs new file mode 100644 index 000000000..5c7f0125a --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterInfo.cs @@ -0,0 +1,74 @@ +using Starward.Core.Gacha; +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterInfo +{ + + [JsonPropertyName("uid")] + [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] + public long Uid { get; set; } + + + [JsonPropertyName("schedule_id")] + public int ScheduleId { get; set; } + + + [JsonPropertyName("start_time")] + [JsonConverter(typeof(DateTimeJsonConverter))] + public DateTime StartTime { get; set; } + + [JsonPropertyName("end_time")] + [JsonConverter(typeof(DateTimeJsonConverter))] + public DateTime EndTime { get; set; } + + /// + /// 难度 + /// + [JsonPropertyName("difficulty_id")] + public int DifficultyId { get; set; } + + /// + /// 抵达最大轮数 + /// + [JsonPropertyName("max_round_id")] + public int MaxRoundId { get; set; } + + /// + /// 纹章类型 + /// + [JsonPropertyName("heraldry")] + public int Heraldry { get; set; } + + /// + /// 明星挑战星章数量 + /// + [JsonPropertyName("medal_num")] + public int MedalNum { get; set; } + + + [JsonPropertyName("detail")] + public ImaginariumTheaterDetail Detail { get; set; } + + + [JsonPropertyName("stat")] + public ImaginariumTheaterStat Stat { get; set; } + + + [JsonPropertyName("schedule")] + public ImaginariumTheaterSchedule Schedule { get; set; } + + + [JsonPropertyName("has_data")] + public bool HasData { get; set; } + + + [JsonPropertyName("has_detail_data")] + public bool HasDetailData { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterLinks.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterLinks.cs new file mode 100644 index 000000000..ff3f9a6d9 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterLinks.cs @@ -0,0 +1,26 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterLinks +{ + [JsonPropertyName("lineup_link")] + public string LineupLink { get; set; } + + [JsonPropertyName("lineup_link_pc")] + public string LineupLinkPc { get; set; } + + [JsonPropertyName("strategy_link")] + public string StrategyLink { get; set; } + + [JsonPropertyName("lineup_publish_link")] + public string LineupPublishLink { get; set; } + + [JsonPropertyName("lineup_publish_link_pc")] + public string LineupPublishLinkPc { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterRoundsData.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterRoundsData.cs new file mode 100644 index 000000000..3a11bd3a6 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterRoundsData.cs @@ -0,0 +1,63 @@ +using Starward.Core.GameRecord.StarRail.SimulatedUniverse; +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterRoundsData +{ + + /// + /// 参演名单 + /// + [JsonPropertyName("avatars")] + public List Avatars { get; set; } + + /// + /// 神秘收获 + /// + [JsonPropertyName("choice_cards")] + public List ChoiceCards { get; set; } + + /// + /// 奇妙助益 + /// + [JsonPropertyName("buffs")] + public List Buffs { get; set; } + + /// + /// 获得明星挑战星章 + /// + [JsonPropertyName("is_get_medal")] + public bool IsGetMedal { get; set; } + + /// + /// 第几轮 + /// + [JsonPropertyName("round_id")] + public int RoundId { get; set; } + + /// + /// 完成时间,timestamp + /// + [JsonPropertyName("finish_time")] + public string FinishTime { get; set; } + + /// + /// 完成时间 + /// + [JsonPropertyName("finish_date_time")] + [JsonConverter(typeof(SimulatedUniverseTimeJsonConverter))] + public DateTime FinishDateTime { get; set; } + + /// + /// 敌人 + /// + [JsonPropertyName("enemies")] + public List Enemies { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterSchedule.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterSchedule.cs new file mode 100644 index 000000000..1b90612d3 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterSchedule.cs @@ -0,0 +1,38 @@ +using Starward.Core.GameRecord.StarRail.SimulatedUniverse; +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterSchedule +{ + /// + /// 开始时间,timestamp + /// + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + /// + /// 结束时间,timestamp + /// + [JsonPropertyName("end_time")] + public string EndTime { get; set; } + + [JsonPropertyName("schedule_type")] + public int ScheduleType { get; set; } + + [JsonPropertyName("schedule_id")] + public int ScheduleId { get; set; } + + [JsonPropertyName("start_date_time")] + [JsonConverter(typeof(SimulatedUniverseTimeJsonConverter))] + public DateTime StartDateTime { get; set; } + + [JsonPropertyName("end_date_time")] + [JsonConverter(typeof(SimulatedUniverseTimeJsonConverter))] + public DateTime EndDateTime { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterStat.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterStat.cs new file mode 100644 index 000000000..492399243 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterStat.cs @@ -0,0 +1,60 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +public class ImaginariumTheaterStat +{ + + /// + /// 难度 + /// + [JsonPropertyName("difficulty_id")] + public int DifficultyId { get; set; } + + /// + /// 抵达最大轮数 + /// + [JsonPropertyName("max_round_id")] + public int MaxRoundId { get; set; } + + /// + /// 纹章类型 + /// + [JsonPropertyName("heraldry")] + public int Heraldry { get; set; } + + /// + /// int[8],0 未获得明星挑战星章,1 获得明星挑战星章 + /// + [JsonPropertyName("get_medal_round_list")] + public List GetMedalRoundList { get; set; } + + /// + /// 明星挑战星章数量 + /// + [JsonPropertyName("medal_num")] + public int MedalNum { get; set; } + + /// + /// 消耗幻剧之花 + /// + [JsonPropertyName("coin_num")] + public int CoinNum { get; set; } + + /// + /// 触发场外观众声援次数 + /// + [JsonPropertyName("avatar_bonus_num")] + public int AvatarBonusNum { get; set; } + + /// + /// 助演角色支援其他玩家次数 + /// + [JsonPropertyName("rent_cnt")] + public int RentCnt { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } +} + diff --git a/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterWarpper.cs b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterWarpper.cs new file mode 100644 index 000000000..76e1c5728 --- /dev/null +++ b/src/Starward.Core/GameRecord/Genshin/ImaginariumTheater/ImaginariumTheaterWarpper.cs @@ -0,0 +1,24 @@ +using System.Text.Json.Serialization; + +namespace Starward.Core.GameRecord.Genshin.ImaginariumTheater; + +internal class ImaginariumTheaterWarpper +{ + + [JsonPropertyName("data")] + public List Data { get; set; } + + + [JsonPropertyName("is_unlock")] + public bool IsUnlock { get; set; } + + + [JsonPropertyName("links")] + public ImaginariumTheaterLinks Links { get; set; } + + + [JsonExtensionData] + public Dictionary? ExtensionData { get; set; } + +} + diff --git a/src/Starward.Core/GameRecord/HoyolabClient.cs b/src/Starward.Core/GameRecord/HoyolabClient.cs index 83c6fdd66..a1cf98ca1 100644 --- a/src/Starward.Core/GameRecord/HoyolabClient.cs +++ b/src/Starward.Core/GameRecord/HoyolabClient.cs @@ -1,4 +1,5 @@ -using Starward.Core.GameRecord.Genshin.SpiralAbyss; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; +using Starward.Core.GameRecord.Genshin.SpiralAbyss; using Starward.Core.GameRecord.Genshin.TravelersDiary; using Starward.Core.GameRecord.StarRail.ApocalypticShadow; using Starward.Core.GameRecord.StarRail.ForgottenHall; @@ -225,6 +226,42 @@ public override async Task GetTravelsDiaryDetailAsync(Game } + + /// + /// 幻想真境剧诗 + /// + /// + /// + /// + public override async Task> GetImaginariumTheaterInfosAsync(GameRecordRole role, CancellationToken cancellationToken = default) + { + var url = $"https://bbs-api-os.hoyolab.com/game_record/app/genshin/api/role_combat?server={role.Region}&role_id={role.Uid}&need_detail=true"; + var request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Add(Cookie, role.Cookie); + request.Headers.Add(DS, CreateSecret2(url)); + request.Headers.Add(Referer, "https://act.hoyolab.com/"); + request.Headers.Add(x_rpc_app_version, AppVersion); + request.Headers.Add(x_rpc_client_type, "5"); + request.Headers.Add(x_rpc_device_id, DeviceId); + request.Headers.Add(x_rpc_device_fp, DeviceFp); + request.Headers.Add(X_Request_With, com_mihoyo_hoyolab); + var warpper = await CommonSendAsync(request, cancellationToken); + foreach (var item in warpper.Data) + { + item.Uid = role.Uid; + item.ScheduleId = item.Schedule.ScheduleId; + item.StartTime = item.Schedule.StartDateTime; + item.EndTime = item.Schedule.EndDateTime; + item.DifficultyId = item.Stat.DifficultyId; + item.MaxRoundId = item.Stat.MaxRoundId; + item.Heraldry = item.Stat.Heraldry; + item.MedalNum = item.Stat.MedalNum; + } + return warpper.Data; + } + + + #endregion diff --git a/src/Starward.Core/GameRecord/HyperionClient.cs b/src/Starward.Core/GameRecord/HyperionClient.cs index 0e4af788f..a6296a090 100644 --- a/src/Starward.Core/GameRecord/HyperionClient.cs +++ b/src/Starward.Core/GameRecord/HyperionClient.cs @@ -1,4 +1,5 @@ -using Starward.Core.GameRecord.Genshin.SpiralAbyss; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; +using Starward.Core.GameRecord.Genshin.SpiralAbyss; using Starward.Core.GameRecord.Genshin.TravelersDiary; using Starward.Core.GameRecord.StarRail.ApocalypticShadow; using Starward.Core.GameRecord.StarRail.ForgottenHall; @@ -272,6 +273,42 @@ public override async Task GetTravelsDiaryDetailAsync(Game } + + /// + /// 幻想真境剧诗 + /// + /// + /// + /// + public override async Task> GetImaginariumTheaterInfosAsync(GameRecordRole role, CancellationToken cancellationToken = default) + { + var url = $"https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/role_combat?server={role.Region}&role_id={role.Uid}&active=1&need_detail=true"; + var request = new HttpRequestMessage(HttpMethod.Get, url); + request.Headers.Add(Cookie, role.Cookie); + request.Headers.Add(DS, CreateSecret2(url)); + request.Headers.Add(Referer, "https://webstatic.mihoyo.com/"); + request.Headers.Add(x_rpc_app_version, AppVersion); + request.Headers.Add(x_rpc_client_type, "5"); + request.Headers.Add(x_rpc_device_id, DeviceId); + request.Headers.Add(x_rpc_device_fp, DeviceFp); + request.Headers.Add(X_Request_With, com_mihoyo_hyperion); + var warpper = await CommonSendAsync(request, cancellationToken); + foreach (var item in warpper.Data) + { + item.Uid = role.Uid; + item.ScheduleId = item.Schedule.ScheduleId; + item.StartTime = item.Schedule.StartDateTime; + item.EndTime = item.Schedule.EndDateTime; + item.DifficultyId = item.Stat.DifficultyId; + item.MaxRoundId = item.Stat.MaxRoundId; + item.Heraldry = item.Stat.Heraldry; + item.MedalNum = item.Stat.MedalNum; + } + return warpper.Data; + } + + + #endregion diff --git a/src/Starward.Language/Lang.Designer.cs b/src/Starward.Language/Lang.Designer.cs index b09906e78..20e7f0bae 100644 --- a/src/Starward.Language/Lang.Designer.cs +++ b/src/Starward.Language/Lang.Designer.cs @@ -1927,6 +1927,15 @@ public static string HoyolabToolboxPage_ForgottenHall { } } + /// + /// 查找类似 Imaginarium Theater 的本地化字符串。 + /// + public static string HoyolabToolboxPage_ImaginariumTheater { + get { + return ResourceManager.GetString("HoyolabToolboxPage_ImaginariumTheater", resourceCulture); + } + } + /// /// 查找类似 Input Cookie 的本地化字符串。 /// @@ -2089,6 +2098,150 @@ public static string ImageViewPage_ZoomOut { } } + /// + /// 查找类似 Act {0} 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_Act0 { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_Act0", resourceCulture); + } + } + + /// + /// 查找类似 Best Record 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_BestRecord { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_BestRecord", resourceCulture); + } + } + + /// + /// 查找类似 Easy Mode 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_EasyMode { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_EasyMode", resourceCulture); + } + } + + /// + /// 查找类似 Fantasia Flowers Used 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_FantasiaFlowersUsed { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_FantasiaFlowersUsed", resourceCulture); + } + } + + /// + /// 查找类似 Hard Mode 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_HardMode { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_HardMode", resourceCulture); + } + } + + /// + /// 查找类似 Highest Damage Dealt 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_HighestDamageDealt { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_HighestDamageDealt", resourceCulture); + } + } + + /// + /// 查找类似 Most Opponents Defeated 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_MostOpponentsDefeated { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_MostOpponentsDefeated", resourceCulture); + } + } + + /// + /// 查找类似 Mystery Cache 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_MysteryCache { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_MysteryCache", resourceCulture); + } + } + + /// + /// 查找类似 Normal Mode 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_NormalMode { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_NormalMode", resourceCulture); + } + } + + /// + /// 查找类似 Past Performances 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_PastPerformances { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_PastPerformances", resourceCulture); + } + } + + /// + /// 查找类似 Star Challenge Stellas 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_StarChallengeStellas { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_StarChallengeStellas", resourceCulture); + } + } + + /// + /// 查找类似 Supporting Cast Characters Assist Other Players 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_SupportingCastCharactersAssistOtherPlayers { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_SupportingCastCharactersAssistOtherPlayers", resourceCulture); + } + } + + /// + /// 查找类似 Team that Completed the Performance Fastest 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_TeamThatCompletedThePerformanceFastest { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_TeamThatCompletedThePerformanceFastest", resourceCulture); + } + } + + /// + /// 查找类似 Total Performance Duration 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_TotalPerformanceDuration { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_TotalPerformanceDuration", resourceCulture); + } + } + + /// + /// 查找类似 Triggered External Audience Support 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_TriggeredExternalAudienceSupport { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_TriggeredExternalAudienceSupport", resourceCulture); + } + } + + /// + /// 查找类似 Wondrous Boon 的本地化字符串。 + /// + public static string ImaginariumTheaterPage_WondrousBoon { + get { + return ResourceManager.GetString("ImaginariumTheaterPage_WondrousBoon", resourceCulture); + } + } + /// /// 查找类似 Click to Restart 的本地化字符串。 /// diff --git a/src/Starward.Language/Lang.resx b/src/Starward.Language/Lang.resx index ab535d86c..f07323974 100644 --- a/src/Starward.Language/Lang.resx +++ b/src/Starward.Language/Lang.resx @@ -1521,4 +1521,56 @@ Do you accept the risk and continue to use it? Retrieve All Data + + Imaginarium Theater + + + Easy Mode + + + Normal Mode + + + Hard Mode + + + Act {0} + Imaginarium Theater Act {0} + + + Past Performances + + + Best Record + + + Star Challenge Stellas + + + Fantasia Flowers Used + + + Triggered External Audience Support + + + Supporting Cast Characters Assist Other Players + + + Total Performance Duration + + + Highest Damage Dealt + + + Most Opponents Defeated + + + Team that Completed the Performance Fastest + + + Wondrous Boon + + + Mystery Cache + \ No newline at end of file diff --git a/src/Starward.Language/Lang.zh-CN.resx b/src/Starward.Language/Lang.zh-CN.resx index 1b659dfb6..1ebac0b51 100644 --- a/src/Starward.Language/Lang.zh-CN.resx +++ b/src/Starward.Language/Lang.zh-CN.resx @@ -59,7 +59,7 @@ : using a System.ComponentModel.TypeConverter : and then encoded with base64 encoding. --> - + @@ -1521,4 +1521,55 @@ 重新获取所有数据 + + 幻想真境剧诗 + + + 轻简模式 + + + 普通模式 + + + 困难模式 + + + 第 {0} 幕 + + + 演出回顾 + + + 最佳纪录 + + + 明星挑战星章 + + + 消耗幻剧之花 + + + 触发场外观众声援 + + + 助演角色支援其他玩家 + + + 演出总时长 + + + 最高伤害输出 + + + 击败最多敌人 + + + 最快完成演出队伍 + + + 奇妙助益 + + + 神秘收获 + \ No newline at end of file diff --git a/src/Starward/Controls/ColorfulTextBlock.xaml b/src/Starward/Controls/ColorfulTextBlock.xaml new file mode 100644 index 000000000..0b0ec303a --- /dev/null +++ b/src/Starward/Controls/ColorfulTextBlock.xaml @@ -0,0 +1,21 @@ + + + + + + diff --git a/src/Starward/Controls/ColorfulTextBlock.xaml.cs b/src/Starward/Controls/ColorfulTextBlock.xaml.cs new file mode 100644 index 000000000..d04d39883 --- /dev/null +++ b/src/Starward/Controls/ColorfulTextBlock.xaml.cs @@ -0,0 +1,129 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Documents; +using Microsoft.UI.Xaml.Media; +using System; +using Windows.UI; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Starward.Controls; + +[INotifyPropertyChanged] +public sealed partial class ColorfulTextBlock : UserControl +{ + + + public ColorfulTextBlock() + { + this.InitializeComponent(); + } + + + + + public TextWrapping TextWrapping + { + get { return (TextWrapping)GetValue(TextWrappingProperty); } + set { SetValue(TextWrappingProperty, value); } + } + + // Using a DependencyProperty as the backing store for TextWrapping. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TextWrappingProperty = + DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(ColorfulTextBlock), new PropertyMetadata(default)); + + + + [ObservableProperty] + private string _text; + partial void OnTextChanged(string value) + { + try + { + var text = ThisTextBlock; + text.Inlines.Clear(); + if (string.IsNullOrWhiteSpace(value)) + { + return; + } + var desc = value.AsSpan(); + int lastIndex = 0; + for (int i = 0; i < desc.Length; i++) + { + // + if (desc[i] == '\\' && desc[i + 1] == 'n') + { + text.Inlines.Add(new Run { Text = desc[lastIndex..i].ToString() }); + text.Inlines.Add(new LineBreak()); + i += 1; + lastIndex = i + 1; + } + // ɫ + if (desc[i] == '<' && desc[i + 1] == 'c') + { + text.Inlines.Add(new Run { Text = desc[lastIndex..i].ToString() }); + var colorLength = desc.Slice(i + 8).IndexOf('>'); + var colorString = desc.Slice(i + 8, colorLength); + var color = Convert.FromHexString(colorString); + var textLength = desc.Slice(i + 9 + colorLength).IndexOf('<'); + if (colorLength == 8) + { + text.Inlines.Add(new Run + { + Text = desc.Slice(i + 9 + colorLength, textLength).ToString(), + Foreground = new SolidColorBrush(Color.FromArgb(color[3], color[0], color[1], color[2])), + }); + } + else if (colorLength == 6) + { + text.Inlines.Add(new Run + { + Text = desc.Slice(i + 9 + colorLength, textLength).ToString(), + Foreground = new SolidColorBrush(Color.FromArgb(0xFF, color[0], color[1], color[2])), + }); + } + else + { + text.Inlines.Add(new Run + { + Text = desc.Slice(i + 9 + colorLength, textLength).ToString(), + }); + } + i += 16 + colorLength + textLength; + lastIndex = i + 1; + } + // + if (desc[i] == '<' && desc[i + 1] == 'i') + { + text.Inlines.Add(new Run { Text = desc[lastIndex..i].ToString() }); + var length = desc.Slice(i + 3).IndexOf('<'); + text.Inlines.Add(new Run + { + Text = desc.Slice(i + 3, length).ToString(), + FontStyle = Windows.UI.Text.FontStyle.Italic, + }); + i += length + 6; + lastIndex = i + 1; + } + // β + if (i == desc.Length - 1) + { + text.Inlines.Add(new Run { Text = desc.Slice(lastIndex).ToString() }); + } + } + } + catch (Exception ex) + { + ThisTextBlock.Inlines.Clear(); + ThisTextBlock.Text = value; + } + } + + + + + + +} diff --git a/src/Starward/Pages/HoyolabToolbox/HoyolabToolboxPage.xaml b/src/Starward/Pages/HoyolabToolbox/HoyolabToolboxPage.xaml index 177cc02f2..6d6c15e8b 100644 --- a/src/Starward/Pages/HoyolabToolbox/HoyolabToolboxPage.xaml +++ b/src/Starward/Pages/HoyolabToolbox/HoyolabToolboxPage.xaml @@ -298,6 +298,23 @@ + + + + + + + + + + + + + typeof(SpiralAbyssPage), + nameof(ImaginariumTheaterPage) => typeof(ImaginariumTheaterPage), nameof(TravelersDiaryPage) => typeof(TravelersDiaryPage), nameof(SimulatedUniversePage) => typeof(SimulatedUniversePage), nameof(ForgottenHallPage) => typeof(ForgottenHallPage), diff --git a/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml b/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml new file mode 100644 index 000000000..3e80e40e7 --- /dev/null +++ b/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml @@ -0,0 +1,554 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml.cs b/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml.cs new file mode 100644 index 000000000..e1d04bb9a --- /dev/null +++ b/src/Starward/Pages/HoyolabToolbox/ImaginariumTheaterPage.xaml.cs @@ -0,0 +1,249 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using Microsoft.Extensions.Logging; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml.Media.Imaging; +using Microsoft.UI.Xaml.Navigation; +using Starward.Core; +using Starward.Core.GameRecord; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; +using Starward.Helpers; +using Starward.Services; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace Starward.Pages.HoyolabToolbox; + +/// +/// An empty page that can be used on its own or navigated to within a Frame. +/// +[INotifyPropertyChanged] +public sealed partial class ImaginariumTheaterPage : PageBase +{ + + private readonly ILogger _logger = AppConfig.GetLogger(); + + private readonly GameRecordService _gameRecordService = AppConfig.GetService(); + + + public ImaginariumTheaterPage() + { + this.InitializeComponent(); + } + + + + private GameRecordRole gameRole; + + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + if (e.Parameter is GameRecordRole role) + { + gameRole = role; + } + } + + + + protected override async void OnLoaded() + { + await Task.Delay(160); + InitializeTheaterData(); + } + + + + + [ObservableProperty] + private bool hasData; + + + + [ObservableProperty] + private List theaterList; + + + [ObservableProperty] + private ImaginariumTheaterInfo? currentTheater; + + + + private void InitializeTheaterData() + { + try + { + CurrentTheater = null; + var list = _gameRecordService.GetImaginariumTheaterInfoList(gameRole); + if (list.Count != 0) + { + TheaterList = list; + ListView_TheaterList.SelectedIndex = 0; + } + else + { + Image_Emoji.Visibility = Visibility.Visible; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Init theater data ({gameBiz}, {uid}).", gameRole?.GameBiz, gameRole?.Uid); + } + } + + + + + [RelayCommand] + private async Task RefreshDataAsync() + { + try + { + if (gameRole is null) + { + return; + } + await _gameRecordService.RefreshImaginariumTheaterInfoAsync(gameRole); + InitializeTheaterData(); + } + catch (miHoYoApiException ex) + { + _logger.LogError(ex, "Refresh theater data ({gameBiz}, {uid}).", gameRole?.GameBiz, gameRole?.Uid); + HoyolabToolboxPage.HandleMiHoYoApiException(ex); + } + catch (HttpRequestException ex) + { + _logger.LogError(ex, "Refresh theater data ({gameBiz}, {uid}).", gameRole?.GameBiz, gameRole?.Uid); + NotificationBehavior.Instance.Warning(Lang.Common_NetworkError, ex.Message); + } + catch (Exception ex) + { + _logger.LogError(ex, "Refresh theater data ({gameBiz}, {uid}).", gameRole?.GameBiz, gameRole?.Uid); + NotificationBehavior.Instance.Error(ex); + } + } + + + + + private void ListView_TheaterList_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + try + { + if (e.AddedItems.FirstOrDefault() is ImaginariumTheaterInfo info) + { + CurrentTheater = _gameRecordService.GetImaginariumTheaterInfo(gameRole, info.ScheduleId); + HasData = CurrentTheater?.HasData ?? false; + Image_Emoji.Visibility = HasData ? Visibility.Collapsed : Visibility.Visible; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "Selection changed ({gameBiz}, {uid}).", gameRole?.GameBiz, gameRole?.Uid); + } + } + + + + + public static string DifficultyMode(int mode) + { + return mode switch + { + 1 => Lang.ImaginariumTheaterPage_EasyMode, + 2 => Lang.ImaginariumTheaterPage_NormalMode, + 3 => Lang.ImaginariumTheaterPage_HardMode, + _ => "", + }; + } + + + + public static string ActX(int x) + { + return string.Format(Lang.ImaginariumTheaterPage_Act0, x); + } + + + + public static Visibility StarIconVisibility(int value) + { + return value == 0 ? Visibility.Collapsed : Visibility.Visible; + } + + + + public static string PerformancesTime(int second) + { + var ts = TimeSpan.FromSeconds(second); + return $"{ts.Minutes}m {ts.Seconds}s"; + } + + + + public static Visibility FightStatisicVisibility(int value) + { + return value == 0 ? Visibility.Collapsed : Visibility.Visible; + } + + + private static BitmapImage Medal0; + private static BitmapImage Medal1; + private static BitmapImage Medal2; + private static BitmapImage Medal3; + + public static BitmapImage? HeraldryImage(int heraldry) + { + return heraldry switch + { + 0 => Medal0 ?? new BitmapImage(new("ms-appx:///Assets/Image/UI_RoleCombat_Medal_0.png")), + 1 => Medal1 ?? new BitmapImage(new("ms-appx:///Assets/Image/UI_RoleCombat_Medal_1.png")), + 2 => Medal2 ?? new BitmapImage(new("ms-appx:///Assets/Image/UI_RoleCombat_Medal_2.png")), + 3 => Medal3 ?? new BitmapImage(new("ms-appx:///Assets/Image/UI_RoleCombat_Medal_3.png")), + _ => null, + }; + } + + + + + public static string DifficultyIdToMaxRound(int difficulty) + { + return difficulty switch + { + 1 => "3", + 2 => "6", + 3 => "8", + _ => "-", + }; + } + + +} + + + +public class TheaterStarIconVisibilityConverter : IValueConverter +{ + + public object Convert(object value, Type targetType, object parameter, string language) + { + return value is 0 ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } +} + + + diff --git a/src/Starward/Services/DatabaseService.cs b/src/Starward/Services/DatabaseService.cs index c299cc53c..499ea87e0 100644 --- a/src/Starward/Services/DatabaseService.cs +++ b/src/Starward/Services/DatabaseService.cs @@ -652,15 +652,28 @@ CREATE TABLE IF NOT EXISTS ZZZQueryItem ItemName TEXT, PRIMARY KEY (Uid, Id) ); - - CREATE INDEX IF NOT EXISTS IX_ZZZQueryItem_Id ON ZZZQueryItem (Id); CREATE INDEX IF NOT EXISTS IX_ZZZQueryItem_Type ON ZZZQueryItem (Type); CREATE INDEX IF NOT EXISTS IX_ZZZQueryItem_Reason ON ZZZQueryItem (Reason); CREATE INDEX IF NOT EXISTS IX_ZZZQueryItem_AddNum ON ZZZQueryItem (AddNum); CREATE INDEX IF NOT EXISTS IX_ZZZQueryItem_DateTime ON ZZZQueryItem (DateTime); - PRAGMA USER_VERSION = 9; + CREATE TABLE IF NOT EXISTS ImaginariumTheaterInfo + ( + Uid INTEGER NOT NULL, + ScheduleId INTEGER NOT NULL, + StartTime TEXT, + EndTime TEXT, + DifficultyId INTEGER NOT NULL, + MaxRoundId INTEGER NOT NULL, + Heraldry INTEGER NOT NULL, + MedalNum INTEGER NOT NULL, + Value TEXT, + PRIMARY KEY (Uid, ScheduleId) + ); + CREATE INDEX IF NOT EXISTS IX_ImaginariumTheaterInfo_ScheduleId ON ImaginariumTheaterInfo (ScheduleId); + + PRAGMA USER_VERSION = 10; COMMIT TRANSACTION; """; diff --git a/src/Starward/Services/GameRecordService.cs b/src/Starward/Services/GameRecordService.cs index 3b97eeb66..1eb77b1e7 100644 --- a/src/Starward/Services/GameRecordService.cs +++ b/src/Starward/Services/GameRecordService.cs @@ -2,6 +2,7 @@ using Microsoft.Extensions.Logging; using Starward.Core; using Starward.Core.GameRecord; +using Starward.Core.GameRecord.Genshin.ImaginariumTheater; using Starward.Core.GameRecord.Genshin.SpiralAbyss; using Starward.Core.GameRecord.Genshin.TravelersDiary; using Starward.Core.GameRecord.StarRail.ApocalypticShadow; @@ -376,6 +377,86 @@ public List GetTravelersDiaryDetailItems(long uid, int + #endregion + + + + + #region Imaginarium Theater + + + + /// + /// 幻想真境剧诗 + /// + /// + /// + /// + public async Task RefreshImaginariumTheaterInfoAsync(GameRecordRole role, CancellationToken cancellationToken = default) + { + var infos = await _gameRecordClient.GetImaginariumTheaterInfosAsync(role, cancellationToken); + if (infos.Count == 0) + { + return; + } + using var dapper = _databaseService.CreateConnection(); + using var t = dapper.BeginTransaction(); + foreach (var info in infos) + { + var obj = new + { + info.Uid, + info.ScheduleId, + info.StartTime, + info.EndTime, + info.DifficultyId, + info.MaxRoundId, + info.Heraldry, + info.MedalNum, + Value = JsonSerializer.Serialize(info, AppConfig.JsonSerializerOptions), + }; + dapper.Execute(""" + INSERT OR REPLACE INTO ImaginariumTheaterInfo (Uid, ScheduleId, StartTime, EndTime, DifficultyId, MaxRoundId, Heraldry, MedalNum, Value) + VALUES (@Uid, @ScheduleId, @StartTime, @EndTime, @DifficultyId, @MaxRoundId, @Heraldry, @MedalNum, @Value); + """, obj, t); + } + t.Commit(); + } + + + + + public List GetImaginariumTheaterInfoList(GameRecordRole role) + { + if (role is null) + { + return new List(); + } + using var dapper = _databaseService.CreateConnection(); + var list = dapper.Query(""" + SELECT Uid, ScheduleId, StartTime, EndTime, DifficultyId, MaxRoundId, Heraldry, MedalNum FROM ImaginariumTheaterInfo WHERE Uid = @Uid ORDER BY ScheduleId DESC; + """, new { role.Uid }); + return list.ToList(); + } + + + + public ImaginariumTheaterInfo? GetImaginariumTheaterInfo(GameRecordRole role, int scheduleId) + { + using var dapper = _databaseService.CreateConnection(); + var value = dapper.QueryFirstOrDefault(""" + SELECT Value FROM ImaginariumTheaterInfo WHERE Uid = @Uid And ScheduleId = @scheduleId LIMIT 1; + """, new { role.Uid, scheduleId }); + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + return JsonSerializer.Deserialize(value); + } + + + + #endregion