From d7057efe1561dd016c5ddb0c9db7557a17200f2c Mon Sep 17 00:00:00 2001 From: Heavy Bob <ferrettclay@gmail.com> Date: Thu, 10 Apr 2025 01:55:35 +1000 Subject: [PATCH] Streamlink - Almost done. --- AutoTrackR2/App.xaml.cs | 2 + AutoTrackR2/ConfigPage.xaml | 407 ++++++++++++++------------- AutoTrackR2/ConfigPage.xaml.cs | 124 ++++---- AutoTrackR2/StreamlinkHandler.cs | 88 ++++++ AutoTrackR2/TrackREventDispatcher.cs | 7 + AutoTrackR2/WebHandler.cs | 21 +- 6 files changed, 385 insertions(+), 264 deletions(-) create mode 100644 AutoTrackR2/StreamlinkHandler.cs diff --git a/AutoTrackR2/App.xaml.cs b/AutoTrackR2/App.xaml.cs index e84d792..e9a45e7 100644 --- a/AutoTrackR2/App.xaml.cs +++ b/AutoTrackR2/App.xaml.cs @@ -19,6 +19,7 @@ namespace AutoTrackR2 "AutoTrackR2", "crash.log" ); + private StreamlinkHandler? _streamlinkHandler; protected override void OnStartup(StartupEventArgs e) { @@ -43,6 +44,7 @@ namespace AutoTrackR2 } base.OnStartup(e); + _streamlinkHandler = new StreamlinkHandler(); } private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) diff --git a/AutoTrackR2/ConfigPage.xaml b/AutoTrackR2/ConfigPage.xaml index b164f23..2ecc235 100644 --- a/AutoTrackR2/ConfigPage.xaml +++ b/AutoTrackR2/ConfigPage.xaml @@ -2,14 +2,13 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="410" - Width="626"> + Width="700"> <Grid Background="{DynamicResource BackgroundLightBrush}"> <!-- Main Layout Grid --> - <Grid Margin="0,0,5,7"> + <Grid> <Grid.RowDefinitions> - <!-- One row for the content, the other for buttons --> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> @@ -22,9 +21,9 @@ </Grid.ColumnDefinitions> <!-- Section for Config Fields --> - <StackPanel Grid.Column="0" - VerticalAlignment="Center" - Height="389"> + <StackPanel Grid.Row="0" + VerticalAlignment="Top" + Margin="20,10,20,0"> <!-- Log File --> <StackPanel Margin="0,5,0,10" Orientation="Horizontal"> @@ -38,11 +37,11 @@ FontSize="16" Margin="0,5,0,5" FontFamily="{StaticResource Roboto}"/> - <StackPanel Orientation="Horizontal" - Margin="30,0,0,0"> + <StackPanel Orientation="Horizontal"> <TextBox Name="LogFilePath" - Width="330" + Width="260" Height="30" + Margin="10,0,0,0" Style="{StaticResource RoundedTextBox}"/> <Button Content="Browse" Width="75" @@ -51,6 +50,13 @@ Margin="5,0" Style="{StaticResource ButtonStyle}" Click="LogFileBrowseButton_Click"/> + <Button Content="Open" + Width="75" + Height="30" + FontFamily="{StaticResource Orbitron}" + Margin="5,0" + Style="{StaticResource ButtonStyle}" + Click="LogFileOpenButton_Click"/> </StackPanel> </StackPanel> @@ -66,11 +72,11 @@ Foreground="{DynamicResource TextBrush}" FontSize="16" Margin="0,5,0,5"/> - <StackPanel Orientation="Horizontal" - Margin="30,0,0,0"> + <StackPanel Orientation="Horizontal"> <TextBox Name="ApiUrl" - Width="330" + Width="260" Height="30" + Margin="10,0,0,0" Style="{StaticResource RoundedTextBox}"/> <Button Content="Test" Width="75" @@ -95,9 +101,9 @@ FontSize="16" Margin="0,5,0,5"/> <PasswordBox Name="ApiKey" - Width="330" + Width="260" Height="30" - Margin="33,0,0,0" + Margin="10,0,0,0" Style="{StaticResource RoundedPasswordBox}"/> </StackPanel> @@ -115,7 +121,7 @@ Margin="0,5,0,5"/> <StackPanel Orientation="Horizontal"> <TextBox Name="VideoPath" - Width="330" + Width="260" Height="30" Margin="10,0,0,0" Style="{StaticResource RoundedTextBox}"/> @@ -126,201 +132,214 @@ Margin="5,0" Style="{StaticResource ButtonStyle}" Click="VideoPathBrowseButton_Click"/> + <Button Content="Open" + Width="75" + Height="30" + FontFamily="{StaticResource Orbitron}" + Margin="5,0" + Style="{StaticResource ButtonStyle}" + Click="VideoPathOpenButton_Click"/> </StackPanel> </StackPanel> <!-- Toggle Settings Grid --> <Grid Margin="0,0,0,10"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="*"/> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> - <!-- Left Column Controls --> - - <!-- Visor Wipe Toggle --> - <StackPanel Grid.Column="0" Grid.Row="0" - Orientation="Horizontal" - Margin="0,0,5,5"> - <TextBlock Text="ⓘ" - ToolTip="Perform a Visor Wipe animation on player kill. Requires AHKv2." - Foreground="{DynamicResource TextBrush}" - FontSize="20" - Margin="0,4,3,0"/> - <TextBlock Text="Visor Wipe:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,0,0"/> - <Slider Name="VisorWipeSlider" - Minimum="0" - Maximum="1" - TickFrequency="1" - IsSnapToTickEnabled="True" - Value="0" - Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" - ValueChanged="VisorWipeSlider_ValueChanged"/> - </StackPanel> + <!-- Left Column Controls --> - <!-- Video Record Toggle --> - <StackPanel Grid.Column="0" Grid.Row="1" - Orientation="Horizontal" - Margin="0,0,5,5"> - <TextBlock Text="ⓘ" - ToolTip="Record video on player kill. Requires AHKv2." - Foreground="{DynamicResource TextBrush}" - FontSize="20" - Margin="0,4,3,0"/> - <TextBlock Text="Video Record:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,0,0"/> - <Slider Name="VideoRecordSlider" - Minimum="0" - Maximum="1" - TickFrequency="1" - IsSnapToTickEnabled="True" - Value="0" - Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" - ValueChanged="VideoRecordSlider_ValueChanged"/> - </StackPanel> + <!-- Visor Wipe Toggle --> + <StackPanel Grid.Column="0" + Grid.Row="0" + Orientation="Horizontal" + Margin="0,0,5,5"> + <TextBlock Text="ⓘ" + ToolTip="Perform a Visor Wipe animation on player kill. Requires AHKv2." + Foreground="{DynamicResource TextBrush}" + FontSize="20" + Margin="0,4,3,0"/> + <TextBlock Text="Visor Wipe:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,0,0"/> + <Slider Name="VisorWipeSlider" + Minimum="0" + Maximum="1" + TickFrequency="1" + IsSnapToTickEnabled="True" + Value="0" + Style="{StaticResource ToggleSliderStyle}" + Margin="10,-4,0,0" + Width="100" + ValueChanged="VisorWipeSlider_ValueChanged"/> + </StackPanel> - <!-- Offline Mode Toggle --> - <StackPanel Grid.Column="0" Grid.Row="2" - Orientation="Horizontal" - Margin="0,0,5,5"> - <TextBlock Text="ⓘ" - ToolTip="With Offline Mode enabled, kills will not be submitted to the configured API." - Foreground="{DynamicResource TextBrush}" - FontSize="20" - Margin="0,4,3,0"/> - <TextBlock Text="Offline Mode:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,0,0"/> - <Slider Name="OfflineModeSlider" - Minimum="0" - Maximum="1" - TickFrequency="1" - IsSnapToTickEnabled="True" - Value="0" - Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" - ValueChanged="OfflineModeSlider_ValueChanged"/> - </StackPanel> + <!-- Video Record Toggle --> + <StackPanel Grid.Column="0" + Grid.Row="1" + Orientation="Horizontal" + Margin="0,0,5,5"> + <TextBlock Text="ⓘ" + ToolTip="Record video on player kill. Requires AHKv2." + Foreground="{DynamicResource TextBrush}" + FontSize="20" + Margin="0,4,3,0"/> + <TextBlock Text="Video Record:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,0,0"/> + <Slider Name="VideoRecordSlider" + Minimum="0" + Maximum="1" + TickFrequency="1" + IsSnapToTickEnabled="True" + Value="0" + Style="{StaticResource ToggleSliderStyle}" + Margin="10,-4,0,0" + Width="100" + ValueChanged="VideoRecordSlider_ValueChanged"/> + </StackPanel> - <!-- Right Column Controls --> - - <!-- Streamlink Toggle --> - <StackPanel Grid.Column="1" Grid.Row="0" - Orientation="Horizontal" - Margin="5,0,0,5"> - <TextBlock Text="ⓘ" - ToolTip="Use Streamlink for video recording." - Foreground="{DynamicResource TextBrush}" - FontSize="20" - Margin="0,4,3,0"/> - <TextBlock Text="Streamlink:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,0,0"/> - <Slider Name="StreamlinkSlider" - Minimum="0" - Maximum="1" - TickFrequency="1" - IsSnapToTickEnabled="True" - Value="0" - Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" - ValueChanged="StreamlinkSlider_ValueChanged"/> - </StackPanel> + <!-- Offline Mode Toggle --> + <StackPanel Grid.Column="0" + Grid.Row="2" + Orientation="Horizontal" + Margin="0,0,5,5"> + <TextBlock Text="ⓘ" + ToolTip="With Offline Mode enabled, kills will not be submitted to the configured API." + Foreground="{DynamicResource TextBrush}" + FontSize="20" + Margin="0,4,3,0"/> + <TextBlock Text="Offline Mode:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,0,0"/> + <Slider Name="OfflineModeSlider" + Minimum="0" + Maximum="1" + TickFrequency="1" + IsSnapToTickEnabled="True" + Value="0" + Style="{StaticResource ToggleSliderStyle}" + Margin="10,-4,0,0" + Width="100" + ValueChanged="OfflineModeSlider_ValueChanged"/> + </StackPanel> - <!-- Streamlink Duration --> - <StackPanel Grid.Column="1" Grid.Row="1" - Orientation="Horizontal" - Margin="5,0,0,5"> - <TextBlock Text="ⓘ" - ToolTip="Duration of Streamlink recordings in seconds." - Foreground="{DynamicResource TextBrush}" - FontSize="20" - Margin="0,4,3,0"/> - <TextBlock Text="Duration:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,0,0"/> - <Slider Name="StreamlinkDurationSlider" - Minimum="10" - Maximum="300" - TickFrequency="10" - IsSnapToTickEnabled="True" - Value="30" - Style="{StaticResource SliderStyle}" - Margin="10,-4,0,0" - Width="100" - ValueChanged="StreamlinkDurationSlider_ValueChanged"/> - <TextBlock Name="StreamlinkDurationText" - Text="30s" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="5,7,0,0"/> - </StackPanel> + <!-- Right Column Controls --> - <!-- Test Streamlink Button --> - <Button Grid.Column="1" Grid.Row="2" - Content="Test Streamlink" - Width="120" - Height="30" - FontFamily="{StaticResource Orbitron}" - Margin="5,0,0,5" - Style="{StaticResource ButtonStyle}" - Click="TestStreamlinkButton_Click"/> + <!-- Streamlink Toggle --> + <StackPanel Grid.Column="1" + Grid.Row="0" + Orientation="Horizontal" + Margin="5,0,0,5"> + <TextBlock Text="ⓘ" + ToolTip="Use Streamlink for video recording." + Foreground="{DynamicResource TextBrush}" + FontSize="20" + Margin="0,4,3,0"/> + <TextBlock Text="Streamlink:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,0,0"/> + <Slider Name="StreamlinkSlider" + Minimum="0" + Maximum="1" + TickFrequency="1" + IsSnapToTickEnabled="True" + Value="0" + Style="{StaticResource ToggleSliderStyle}" + Margin="10,-4,0,0" + Width="100" + ValueChanged="StreamlinkSlider_ValueChanged"/> + </StackPanel> - <!-- Theme Slider --> - <StackPanel Grid.Column="0" Grid.Row="4" - Grid.ColumnSpan="2" - Orientation="Horizontal" - Margin="0,10,0,5"> - <TextBlock Text="Theme:" - Foreground="{DynamicResource TextBrush}" - FontSize="16" - Margin="0,7,10,0"/> - <Slider x:Name="ThemeSlider" - Minimum="0" - Value="0" - TickFrequency="1" - IsSnapToTickEnabled="True" - ValueChanged="ThemeSlider_ValueChanged" - Width="447" - Style="{StaticResource ThreePositionSlider}"/> - </StackPanel> + <!-- Streamlink Duration --> + <StackPanel Grid.Column="1" + Grid.Row="1" + Orientation="Horizontal" + Margin="5,0,0,5"> + <TextBlock Text="ⓘ" + ToolTip="Duration of Streamlink recordings in seconds." + Foreground="{DynamicResource TextBrush}" + FontSize="20" + Margin="0,4,3,0"/> + <TextBlock Text="Duration:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,0,0"/> + <Slider Name="StreamlinkDurationSlider" + Minimum="10" + Maximum="600" + TickFrequency="30" + IsSnapToTickEnabled="True" + Value="30" + Style="{StaticResource SliderStyle}" + Margin="10,-4,0,0" + Width="100" + ValueChanged="StreamlinkDurationSlider_ValueChanged"/> + <TextBlock Name="StreamlinkDurationText" + Text="30s" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="5,7,0,0"/> + </StackPanel> + + <!-- Test Streamlink Button --> + <Button Grid.Column="1" + Grid.Row="2" + Content="Test Streamlink" + Width="120" + Height="30" + FontFamily="{StaticResource Orbitron}" + Margin="5,0,0,5" + Style="{StaticResource ButtonStyle}" + Click="TestStreamlinkButton_Click"/> + + <!-- Theme Slider --> + <StackPanel Grid.Column="0" + Grid.Row="3" + Grid.ColumnSpan="2" + Orientation="Horizontal" + Margin="0,0,0,5"> + <TextBlock Text="Theme:" + Foreground="{DynamicResource TextBrush}" + FontSize="16" + Margin="0,7,10,0"/> + <Slider x:Name="ThemeSlider" + Minimum="0" + Value="0" + TickFrequency="1" + IsSnapToTickEnabled="True" + ValueChanged="ThemeSlider_ValueChanged" + Width="350" + Style="{StaticResource ThreePositionSlider}"/> + </StackPanel> </Grid> </StackPanel> <!-- Save Button --> - <StackPanel Grid.Column="2" - HorizontalAlignment="Right" - VerticalAlignment="Bottom" - Margin="0,0,0,10"> - <Button x:Name="SaveButton" - Content="Save" - Width="100" - Height="40" - Style="{StaticResource ButtonStyle}" - FontFamily="{StaticResource Orbitron}" - Click="SaveButton_Click"/> - </StackPanel> + <Button x:Name="SaveButton" + Grid.Row="1" + Content="Save" + Width="100" + Height="40" + Style="{StaticResource ButtonStyle}" + FontFamily="{StaticResource Orbitron}" + HorizontalAlignment="Right" + VerticalAlignment="Bottom" + Margin="0,0,80,20" + Click="SaveButton_Click"/> </Grid> </Grid> </UserControl> diff --git a/AutoTrackR2/ConfigPage.xaml.cs b/AutoTrackR2/ConfigPage.xaml.cs index 569041d..284f835 100644 --- a/AutoTrackR2/ConfigPage.xaml.cs +++ b/AutoTrackR2/ConfigPage.xaml.cs @@ -37,9 +37,18 @@ public partial class ConfigPage : UserControl VideoRecordSlider.Value = ConfigManager.VideoRecord; OfflineModeSlider.Value = ConfigManager.OfflineMode; ThemeSlider.Value = ConfigManager.Theme; + StreamlinkSlider.Value = ConfigManager.StreamlinkEnabled; + StreamlinkDurationSlider.Value = ConfigManager.StreamlinkDuration; // Initialize Streamlink slider style - StreamlinkSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + if (StreamlinkSlider.Value == 0) + { + StreamlinkSlider.Style = (Style)Application.Current.FindResource("FalseToggleStyle"); + } + else + { + StreamlinkSlider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle"); + } ApplyToggleModeStyle(OfflineModeSlider.Value, VisorWipeSlider.Value, VideoRecordSlider.Value); @@ -430,6 +439,19 @@ public partial class ConfigPage : UserControl private void StreamlinkSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { Slider slider = (Slider)sender; + + // Only allow enabling if streamlink is installed + if (slider.Value == 1) + { + if (!StreamlinkHandler.IsStreamlinkInstalled()) + { + MessageBox.Show("Streamlink is not installed. Please install Streamlink to use this feature.", + "Error", MessageBoxButton.OK, MessageBoxImage.Error); + slider.Value = 0; + return; + } + } + ConfigManager.StreamlinkEnabled = (int)slider.Value; // Apply the appropriate style based on the value @@ -459,82 +481,46 @@ public partial class ConfigPage : UserControl { // Get the duration from the slider int duration = (int)StreamlinkDurationSlider.Value; - - // Check if streamlink is installed - var versionInfo = new ProcessStartInfo - { - FileName = "streamlink", - Arguments = "--version", - UseShellExecute = false, - RedirectStandardOutput = true, - CreateNoWindow = true - }; - using (var process = Process.Start(versionInfo)) - { - if (process == null) - { - MessageBox.Show("Streamlink is not installed. Please install Streamlink to use this feature.", - "Error", MessageBoxButton.OK, MessageBoxImage.Error); - return; - } + // Calculate the total duration (30 seconds before + configured duration) + int totalDuration = 30 + duration; - string output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - - if (process.ExitCode != 0) - { - MessageBox.Show("Streamlink is not installed or not working correctly. Please install Streamlink to use this feature.", - "Error", MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - } - - // Test recording functionality - var testUrl = "https://www.twitch.tv/starcitizen"; // Example URL for testing - var outputPath = Path.Combine( - ConfigManager.VideoPath ?? Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), - "streamlink_test.mp4" - ); - - var recordInfo = new ProcessStartInfo - { - FileName = "streamlink", - Arguments = $"{testUrl} best -o {outputPath}", - UseShellExecute = false, - RedirectStandardOutput = true, - CreateNoWindow = true - }; - - using (var process = Process.Start(recordInfo)) - { - if (process == null) - { - MessageBox.Show("Failed to start test recording.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - - // Wait for a short duration (5 seconds) to test recording - await Task.Delay(5000); - - try - { - if (!process.HasExited) - { - process.Kill(); - } - } - catch { } - } - - MessageBox.Show($"Streamlink test recording completed successfully.\nA 5-second test recording was saved to:\n{outputPath}", - "Success", MessageBoxButton.OK, MessageBoxImage.Information); + // Test recording functionality, we're using spacecutlet cause need a good tester. + TrackREventDispatcher.OnStreamlinkRecordEvent("spacecutlet"); } catch (Exception ex) { MessageBox.Show($"Error testing Streamlink: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } } + + private void LogFileOpenButton_Click(object sender, RoutedEventArgs e) + { + if (!string.IsNullOrEmpty(LogFilePath.Text)) + { + string directory = Path.GetDirectoryName(LogFilePath.Text) ?? string.Empty; + if (Directory.Exists(directory)) + { + Process.Start("explorer.exe", directory); + } + else + { + MessageBox.Show("Directory does not exist.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + } + + private void VideoPathOpenButton_Click(object sender, RoutedEventArgs e) + { + if (!string.IsNullOrEmpty(VideoPath.Text) && Directory.Exists(VideoPath.Text)) + { + Process.Start("explorer.exe", VideoPath.Text); + } + else + { + MessageBox.Show("Directory does not exist.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } } public class Theme diff --git a/AutoTrackR2/StreamlinkHandler.cs b/AutoTrackR2/StreamlinkHandler.cs new file mode 100644 index 0000000..f384d61 --- /dev/null +++ b/AutoTrackR2/StreamlinkHandler.cs @@ -0,0 +1,88 @@ +using System.Diagnostics; +using System.IO; + +namespace AutoTrackR2; + +public class StreamlinkHandler +{ + public StreamlinkHandler() + { + TrackREventDispatcher.StreamlinkRecordEvent += HandleStreamlinkRecord; + } + + public static bool IsStreamlinkInstalled() + { + try + { + var checkInfo = new ProcessStartInfo + { + FileName = "where", + Arguments = "streamlink", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (var process = Process.Start(checkInfo)) + { + if (process == null) + { + return false; + } + + string output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + return process.ExitCode == 0 && !string.IsNullOrEmpty(output); + } + } + catch + { + return false; + } + } + + private async void HandleStreamlinkRecord(string streamerHandle) + { + if (ConfigManager.StreamlinkEnabled != 1) + { + return; + } + + try + { + var outputPath = Path.Combine( + ConfigManager.VideoPath ?? Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), + $"kill_{DateTime.Now:yyyyMMdd_HHmmss}.mp4" + ); + + // Calculate the duration for recording (30 seconds before + configured duration after) + var totalDuration = 30 + ConfigManager.StreamlinkDuration; + + var recordInfo = new ProcessStartInfo + { + FileName = "streamlink", + Arguments = $"https://www.twitch.tv/{streamerHandle} best --hls-live-edge 30 --hls-duration {totalDuration} -o {outputPath}", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using (var process = Process.Start(recordInfo)) + { + if (process == null) + { + return; + } + + // Wait for the recording to complete + await process.WaitForExitAsync(); + } + } + catch (Exception ex) + { + // Log the error but don't crash the application + Debug.WriteLine($"Error recording streamlink clip: {ex.Message}"); + } + } +} \ No newline at end of file diff --git a/AutoTrackR2/TrackREventDispatcher.cs b/AutoTrackR2/TrackREventDispatcher.cs index d5dc3ae..36823ac 100644 --- a/AutoTrackR2/TrackREventDispatcher.cs +++ b/AutoTrackR2/TrackREventDispatcher.cs @@ -54,4 +54,11 @@ public static class TrackREventDispatcher { JumpDriveStateChangedEvent?.Invoke(data); } + + public static event Action<string>? StreamlinkRecordEvent; + + public static void OnStreamlinkRecordEvent(string streamerHandle) + { + StreamlinkRecordEvent?.Invoke(streamerHandle); + } } \ No newline at end of file diff --git a/AutoTrackR2/WebHandler.cs b/AutoTrackR2/WebHandler.cs index fd2b646..c18d440 100644 --- a/AutoTrackR2/WebHandler.cs +++ b/AutoTrackR2/WebHandler.cs @@ -172,7 +172,26 @@ public static class WebHandler else if (response.StatusCode == HttpStatusCode.OK) { Console.WriteLine("Successfully submitted kill data"); - Console.WriteLine($"Response: {await response.Content.ReadAsStringAsync()}"); + var responseContent = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Response: {responseContent}"); + + // Check if the response contains a streamer field + try + { + var responseData = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(responseContent); + if (responseData != null && responseData.TryGetValue("streamer", out JsonElement streamerElement)) + { + string streamerHandle = streamerElement.GetString() ?? string.Empty; + if (!string.IsNullOrEmpty(streamerHandle)) + { + TrackREventDispatcher.OnStreamlinkRecordEvent(streamerHandle); + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Error parsing streamer from response: {ex.Message}"); + } } } } \ No newline at end of file