using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net.Http; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Threading; using System.Xaml; using Microsoft.WindowsAPICodePack.Dialogs; #nullable enable namespace BililiveRecorder.WPF.Pages { /// /// Interaction logic for AnnouncementPage.xaml /// public partial class AnnouncementPage { private static readonly HttpClient client; private static MemoryStream? AnnouncementCache = null; private static DateTimeOffset AnnouncementCacheTime = DateTimeOffset.MinValue; internal static CultureInfo CultureInfo = CultureInfo.CurrentUICulture; static AnnouncementPage() { client = new HttpClient(); client.DefaultRequestHeaders.Add("User-Agent", $"BililiveRecorder/{GitVersionInformation.FullSemVer}"); } public AnnouncementPage() { this.InitializeComponent(); _ = this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Func)(async () => await this.LoadAnnouncementAsync(ignore_cache: false, show_error: false))); } #pragma warning disable VSTHRD100 // Avoid async void methods private async void Button_Click(object sender, RoutedEventArgs e) #pragma warning restore VSTHRD100 // Avoid async void methods { try { await this.LoadAnnouncementAsync(ignore_cache: true, show_error: Keyboard.Modifiers.HasFlag(ModifierKeys.Control)); } catch (Exception) { } } private async Task LoadAnnouncementAsync(bool ignore_cache, bool show_error) { MemoryStream? data; bool success; this.Container.Child = null; this.Error.Visibility = Visibility.Collapsed; this.Loading.Visibility = Visibility.Visible; if (AnnouncementCache is not null && !ignore_cache) { data = AnnouncementCache; success = true; } else { try { var uri = Debugger.IsAttached ? $"http://rec.127-0-0-1.nip.io/wpf/announcement.php?c={CultureInfo.Name}" : $"https://rec.danmuji.org/wpf/announcement.xml?c={CultureInfo.Name}"; var resp = await client.GetAsync(uri); var stream = await resp.EnsureSuccessStatusCode().Content.ReadAsStreamAsync(); var mstream = new MemoryStream(); await stream.CopyToAsync(mstream); AnnouncementCacheTime = DateTimeOffset.Now; data = mstream; success = true; } catch (Exception ex) { data = null; success = false; if (show_error) MessageBox.Show(ex.ToString(), "Loading Error"); } } if (success && data is not null) { try { using var stream = new MemoryStream(); data.Position = 0; await data.CopyToAsync(stream); stream.Position = 0; using var reader = new XamlXmlReader(stream, System.Windows.Markup.XamlReader.GetWpfSchemaContext()); var obj = System.Windows.Markup.XamlReader.Load(reader); if (obj is UIElement elem) this.Container.Child = elem; } catch (Exception ex) { data = null; success = false; if (show_error) MessageBox.Show(ex.ToString(), "Loading Error"); } } this.Loading.Visibility = Visibility.Collapsed; if (success) { this.RefreshButton.ToolTip = "Load Time: " + AnnouncementCacheTime.ToString("F"); AnnouncementCache = data; } else { this.RefreshButton.ToolTip = null; this.Error.Visibility = Visibility.Visible; } } #pragma warning disable VSTHRD100 // Avoid async void methods private async void Button_MouseRightButtonUp(object sender, MouseButtonEventArgs e) #pragma warning restore VSTHRD100 // Avoid async void methods { if (!Keyboard.Modifiers.HasFlag(ModifierKeys.Control) || !Keyboard.Modifiers.HasFlag(ModifierKeys.Alt)) return; var fileDialog = new CommonOpenFileDialog() { IsFolderPicker = false, Multiselect = false, Title = "Load local file", AddToMostRecentlyUsedList = false, EnsurePathExists = true, NavigateToShortcut = true, }; if (fileDialog.ShowDialog() == CommonFileDialogResult.Ok) { try { var ms = new MemoryStream(); using (var fs = File.OpenRead(fileDialog.FileName)) { await fs.CopyToAsync(ms); } AnnouncementCache = ms; AnnouncementCacheTime = DateTimeOffset.Now; } catch (Exception ex) { MessageBox.Show(ex.ToString(), "Loading Error"); } await this.LoadAnnouncementAsync(ignore_cache: false, show_error: true); } } } }