// // MeoAsstGui - A part of the MeoAssistantArknights project // Copyright (C) 2021 MistEO and Contributors // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY // using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Stylet; using StyletIoC; using DataFormats = System.Windows.Forms.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; using Screen = Stylet.Screen; namespace MeoAsstGui { /// /// The view model of copilot. /// public class CopilotViewModel : Screen { private readonly IWindowManager _windowManager; private readonly IContainer _container; /// /// Gets or sets the view models of log items. /// public ObservableCollection LogItemViewModels { get; set; } /// /// Initializes a new instance of the class. /// /// The IoC container. /// The window manager. public CopilotViewModel(IContainer container, IWindowManager windowManager) { _container = container; _windowManager = windowManager; DisplayName = Localization.GetString("Copilot"); LogItemViewModels = new ObservableCollection(); AddLog( Localization.GetString("CopilotTip") + "\n\n" + Localization.GetString("CopilotTip1") + "\n\n" + Localization.GetString("CopilotTip2") + "\n\n" + Localization.GetString("CopilotTip3") + "\n\n" + Localization.GetString("CopilotTip4"), /* Localization.GetString("CopilotTip5"),*/ LogColor.Message); } /// /// Adds log. /// /// The content. /// The font color. /// The font weight. public void AddLog(string content, string color = LogColor.Trace, string weight = "Regular") { LogItemViewModels.Add(new LogItemViewModel(content, color, weight)); // LogItemViewModels.Insert(0, new LogItemViewModel(time + content, color, weight)); } /// /// Adds log with URL. /// /// The content. /// The URL. /// The font color. /// The font weight. public void AddLogWithUrl(string content, string url, string color = LogColor.Trace, string weight = "Regular") { LogItemViewModels.Add(new LogItemViewModel(content, color, weight)); // LogItemViewModels.Insert(0, new LogItemViewModel(time + content, color, weight)); } private bool _idle = true; /// /// Gets or sets a value indicating whether it is idle. /// public bool Idle { get => _idle; set { _idle = value; NotifyOfPropertyChange(() => Idle); } } /// /// Clears log. /// public void ClearLog() { LogItemViewModels.Clear(); } private string _filename = string.Empty; /// /// Gets or sets the filename. /// public string Filename { get => _filename; set { SetAndNotify(ref _filename, value); ClearLog(); UpdateFileDoc(_filename); } } private const string CopilotIdPrefix = "maa://"; private void UpdateFileDoc(string filename) { string jsonStr = string.Empty; if (File.Exists(filename)) { try { jsonStr = File.ReadAllText(filename); } catch (Exception) { AddLog(Localization.GetString("CopilotFileReadError"), LogColor.Error); return; } } else if (int.TryParse(filename, out _)) { int.TryParse(filename, out int copilotID); jsonStr = RequestCopilotServer(copilotID); } else if (filename.ToLower().StartsWith(CopilotIdPrefix)) { var copilotIdStr = filename.ToLower().Remove(0, CopilotIdPrefix.Length); int.TryParse(copilotIdStr, out int copilotID); jsonStr = RequestCopilotServer(copilotID); } else { EasterEgg(filename); return; } if (jsonStr != string.Empty) { ParseJsonAndShowInfo(jsonStr); } } private string RequestCopilotServer(int copilotID) { try { // 创建 Http 请求 var httpWebRequest = WebRequest.Create($@"https://api.prts.plus/copilot/get/{copilotID}") as HttpWebRequest; httpWebRequest.Method = "GET"; httpWebRequest.ContentType = "application/json"; var httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse; // 获取输入输出流 using (var sr = new StreamReader(httpWebResponse.GetResponseStream())) { var text = sr.ReadToEnd(); var responseObject = (JObject)JsonConvert.DeserializeObject(text); if (responseObject != null && responseObject.ContainsKey("status_code") && responseObject["status_code"].ToString() == "200") { return responseObject["data"]["content"].ToString(); } else { AddLog(Localization.GetString("CopilotNoFound"), LogColor.Error); return string.Empty; } } } catch (Exception) { AddLog(Localization.GetString("NetworkServiceError"), LogColor.Error); return string.Empty; } } private string _curStageName = string.Empty; private string _curCopilotData = string.Empty; private const string TempCopilotFile = "resource/_temp_copilot.json"; private void ParseJsonAndShowInfo(string jsonStr) { try { _curCopilotData = string.Empty; var json = (JObject)JsonConvert.DeserializeObject(jsonStr); if (json == null) { AddLog(Localization.GetString("CopilotJsonError"), LogColor.Error); return; } var doc = (JObject)json["doc"]; string title = string.Empty; if (doc != null && doc.ContainsKey("title")) { title = doc["title"].ToString(); } if (title.Length != 0) { string title_color = LogColor.Message; if (doc.ContainsKey("title_color")) { title_color = doc["title_color"].ToString(); } AddLog(title, title_color); } string details = string.Empty; if (doc != null && doc.ContainsKey("details")) { details = doc["details"].ToString(); } if (details.Length != 0) { string details_color = LogColor.Message; if (doc.ContainsKey("details_color")) { details_color = doc["details_color"].ToString(); } AddLog(details, details_color); { Url = CopilotUiUrl; var linkParser = new Regex(@"(BV.*?).{10}", RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (Match match in linkParser.Matches(details)) { Url = "https://www.bilibili.com/video/" + match.Value; break; } if (string.IsNullOrEmpty(Url)) { linkParser = new Regex(@"(?:https?://)\S+\b", RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (Match m in linkParser.Matches(details)) { Url = m.Value; break; } } } } AddLog(string.Empty, LogColor.Message); int count = 0; foreach (var oper in json["opers"].Cast()) { count++; AddLog(string.Format("{0}, {1} 技能", oper["name"], oper["skill"]), LogColor.Message); } if (json.ContainsKey("groups")) { foreach (var group in json["groups"].Cast()) { count++; string group_name = group["name"] + ": "; var operInfos = new List(); foreach (var oper in group["opers"].Cast()) { operInfos.Add(string.Format("{0} {1}", oper["name"], oper["skill"])); } AddLog(group_name + string.Join(" / ", operInfos), LogColor.Message); } } AddLog(string.Format("共 {0} 名干员", count), LogColor.Message); _curStageName = json["stage_name"].ToString(); _curCopilotData = json.ToString(); AddLog( "\n\n" + Localization.GetString("CopilotTip") + "\n\n" + Localization.GetString("CopilotTip1") + "\n\n" + Localization.GetString("CopilotTip2") + "\n\n" + Localization.GetString("CopilotTip3") + "\n\n" + Localization.GetString("CopilotTip4")); /* Localization.GetString("CopilotTip5"));*/ } catch (Exception) { AddLog(Localization.GetString("CopilotJsonError"), LogColor.Error); } } /// /// Selects file. /// public void SelectFile() { var dialog = new Microsoft.Win32.OpenFileDialog { Filter = "JSON|*.json", }; if (dialog.ShowDialog() == true) { Filename = dialog.FileName; } } /// /// Drops file. /// /// The sender. /// The event arguments. public void DropFile(object sender, DragEventArgs e) { if (!e.Data.GetDataPresent(DataFormats.FileDrop)) { return; } var filename = ((Array)e.Data.GetData(DataFormats.FileDrop))?.GetValue(0).ToString(); if (filename == null) { return; } if (filename.EndsWith(".json")) { Filename = filename; } else { Filename = string.Empty; ClearLog(); AddLog(Localization.GetString("NotCopilotJson"), LogColor.Error); } } private bool _form = false; /// /// Gets or sets a value indicating whether to use auto-formation. /// public bool Form { get => _form; set => SetAndNotify(ref _form, value); } private bool _caught = false; /// /// Starts copilot. /// public async void Start() { ClearLog(); /* if (_form) { AddLog(Localization.GetString("AutoSquadTip"), LogColor.Message); }*/ AddLog(Localization.GetString("ConnectingToEmulator")); var asstProxy = _container.Get(); string errMsg = string.Empty; var task = Task.Run(() => { return asstProxy.AsstConnect(ref errMsg); }); _caught = await task; if (!_caught) { AddLog(errMsg, LogColor.Error); return; } if (errMsg.Length != 0) { AddLog(errMsg, LogColor.Error); } UpdateFileDoc(Filename); File.Delete(TempCopilotFile); File.WriteAllText(TempCopilotFile, _curCopilotData); bool ret = asstProxy.AsstStartCopilot(_curStageName, TempCopilotFile, Form); if (ret) { Idle = false; AddLog("Star Burst Stream!"); } else { AddLog(Localization.GetString("CopilotFileReadError") + "\n" + Localization.GetString("CheckTheFile"), LogColor.Error); } } /// /// Stops copilot. /// public void Stop() { var asstProxy = _container.Get(); asstProxy.AsstStop(); Idle = true; } private const string CopilotUiUrl = "https://www.prts.plus/"; private string _url = CopilotUiUrl; /// /// Gets or sets the copilot URL. /// public string Url { get => _url == CopilotUiUrl ? Localization.GetString("CopilotJSONSharing") : Localization.GetString("VideoLink"); set => SetAndNotify(ref _url, value); } /// /// The event handler of clicking hyperlink. /// public void Hyperlink_Click() { try { if (!string.IsNullOrEmpty(_url)) { Process.Start(new ProcessStartInfo(_url)); } } catch (Exception) { } } /// /// 点击后移除界面中元素焦点 /// /// 点击事件发送者 /// 点击事件 public void MouseDown(object sender, MouseButtonEventArgs e) { if (!(sender is UIElement element)) { return; } DependencyObject scope = FocusManager.GetFocusScope(element); FocusManager.SetFocusedElement(scope, element); Keyboard.ClearFocus(); } /// /// 回车键点击后移除界面中元素焦点 /// /// 点击事件发送者 /// 点击事件 public void KeyDown(object sender, KeyEventArgs e) { if (e.Key != Key.Enter) { return; } if (!(sender is UIElement element)) { return; } DependencyObject scope = FocusManager.GetFocusScope(element); FocusManager.SetFocusedElement(scope, element); Keyboard.ClearFocus(); } private void EasterEgg(string text) { switch (text) { case "/help": AddLog(Localization.GetString("HelloWorld"), LogColor.Message); break; } } } }