mirror of
https://github.com/BubbaGumpShrump/AutoTrackR2.git
synced 2025-06-21 14:09:07 +00:00
Compare commits
4 commits
1e0cf4ce0d
...
b448cfec3c
Author | SHA1 | Date | |
---|---|---|---|
|
b448cfec3c | ||
|
5994743c73 | ||
|
d7057efe15 | ||
|
f7fb63c50f |
9 changed files with 607 additions and 173 deletions
|
@ -571,5 +571,55 @@
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Standard Slider Style -->
|
||||||
|
<Style x:Key="SliderStyle" TargetType="Slider">
|
||||||
|
<Setter Property="Height" Value="40"/>
|
||||||
|
<Setter Property="Width" Value="160"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource TextBrush}"/>
|
||||||
|
<Setter Property="Background" Value="{DynamicResource BackgroundDarkBrush}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource AccentBrush}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="2"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Slider">
|
||||||
|
<Grid Width="100" Height="30" HorizontalAlignment="Left">
|
||||||
|
<!-- Track Background -->
|
||||||
|
<Border Background="{DynamicResource BackgroundDarkBrush}"
|
||||||
|
BorderBrush="{DynamicResource AccentBrush}"
|
||||||
|
BorderThickness="2"
|
||||||
|
CornerRadius="15"
|
||||||
|
Margin="0,0,-5,-4"/>
|
||||||
|
|
||||||
|
<!-- Track -->
|
||||||
|
<Track x:Name="PART_Track">
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb x:Name="PART_Thumb"
|
||||||
|
Width="22"
|
||||||
|
Height="22"
|
||||||
|
Margin="6,4,1,0">
|
||||||
|
<Thumb.Template>
|
||||||
|
<ControlTemplate TargetType="Thumb">
|
||||||
|
<Ellipse Fill="{DynamicResource AccentBrush}"/>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Thumb.Template>
|
||||||
|
</Thumb>
|
||||||
|
</Track.Thumb>
|
||||||
|
<Track.DecreaseRepeatButton>
|
||||||
|
<RepeatButton Background="Transparent"
|
||||||
|
BorderBrush="Transparent"
|
||||||
|
IsHitTestVisible="False"/>
|
||||||
|
</Track.DecreaseRepeatButton>
|
||||||
|
<Track.IncreaseRepeatButton>
|
||||||
|
<RepeatButton Background="Transparent"
|
||||||
|
BorderBrush="Transparent"
|
||||||
|
IsHitTestVisible="False"/>
|
||||||
|
</Track.IncreaseRepeatButton>
|
||||||
|
</Track>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace AutoTrackR2
|
||||||
"AutoTrackR2",
|
"AutoTrackR2",
|
||||||
"crash.log"
|
"crash.log"
|
||||||
);
|
);
|
||||||
|
private StreamlinkHandler? _streamlinkHandler;
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
|
@ -43,6 +44,7 @@ namespace AutoTrackR2
|
||||||
}
|
}
|
||||||
|
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
_streamlinkHandler = new StreamlinkHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
|
|
|
@ -2,14 +2,13 @@
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
Height="410"
|
Height="410"
|
||||||
Width="626">
|
Width="700">
|
||||||
|
|
||||||
|
|
||||||
<Grid Background="{DynamicResource BackgroundLightBrush}">
|
<Grid Background="{DynamicResource BackgroundLightBrush}">
|
||||||
<!-- Main Layout Grid -->
|
<!-- Main Layout Grid -->
|
||||||
<Grid Margin="0,0,5,7">
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<!-- One row for the content, the other for buttons -->
|
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
@ -22,9 +21,9 @@
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<!-- Section for Config Fields -->
|
<!-- Section for Config Fields -->
|
||||||
<StackPanel Grid.Column="0"
|
<StackPanel Grid.Row="0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Top"
|
||||||
Height="389">
|
Margin="20,10,20,0">
|
||||||
<!-- Log File -->
|
<!-- Log File -->
|
||||||
<StackPanel Margin="0,5,0,10"
|
<StackPanel Margin="0,5,0,10"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
|
@ -38,11 +37,11 @@
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Margin="0,5,0,5"
|
Margin="0,5,0,5"
|
||||||
FontFamily="{StaticResource Roboto}"/>
|
FontFamily="{StaticResource Roboto}"/>
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal">
|
||||||
Margin="30,0,0,0">
|
|
||||||
<TextBox Name="LogFilePath"
|
<TextBox Name="LogFilePath"
|
||||||
Width="330"
|
Width="260"
|
||||||
Height="30"
|
Height="30"
|
||||||
|
Margin="10,0,0,0"
|
||||||
Style="{StaticResource RoundedTextBox}"/>
|
Style="{StaticResource RoundedTextBox}"/>
|
||||||
<Button Content="Browse"
|
<Button Content="Browse"
|
||||||
Width="75"
|
Width="75"
|
||||||
|
@ -51,6 +50,13 @@
|
||||||
Margin="5,0"
|
Margin="5,0"
|
||||||
Style="{StaticResource ButtonStyle}"
|
Style="{StaticResource ButtonStyle}"
|
||||||
Click="LogFileBrowseButton_Click"/>
|
Click="LogFileBrowseButton_Click"/>
|
||||||
|
<Button Content="Open"
|
||||||
|
Width="75"
|
||||||
|
Height="30"
|
||||||
|
FontFamily="{StaticResource Orbitron}"
|
||||||
|
Margin="5,0"
|
||||||
|
Style="{StaticResource ButtonStyle}"
|
||||||
|
Click="LogFileOpenButton_Click"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
@ -66,11 +72,11 @@
|
||||||
Foreground="{DynamicResource TextBrush}"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Margin="0,5,0,5"/>
|
Margin="0,5,0,5"/>
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal">
|
||||||
Margin="30,0,0,0">
|
|
||||||
<TextBox Name="ApiUrl"
|
<TextBox Name="ApiUrl"
|
||||||
Width="330"
|
Width="260"
|
||||||
Height="30"
|
Height="30"
|
||||||
|
Margin="10,0,0,0"
|
||||||
Style="{StaticResource RoundedTextBox}"/>
|
Style="{StaticResource RoundedTextBox}"/>
|
||||||
<Button Content="Test"
|
<Button Content="Test"
|
||||||
Width="75"
|
Width="75"
|
||||||
|
@ -95,9 +101,9 @@
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
Margin="0,5,0,5"/>
|
Margin="0,5,0,5"/>
|
||||||
<PasswordBox Name="ApiKey"
|
<PasswordBox Name="ApiKey"
|
||||||
Width="330"
|
Width="260"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="33,0,0,0"
|
Margin="10,0,0,0"
|
||||||
Style="{StaticResource RoundedPasswordBox}"/>
|
Style="{StaticResource RoundedPasswordBox}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
@ -115,7 +121,7 @@
|
||||||
Margin="0,5,0,5"/>
|
Margin="0,5,0,5"/>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBox Name="VideoPath"
|
<TextBox Name="VideoPath"
|
||||||
Width="330"
|
Width="260"
|
||||||
Height="30"
|
Height="30"
|
||||||
Margin="10,0,0,0"
|
Margin="10,0,0,0"
|
||||||
Style="{StaticResource RoundedTextBox}"/>
|
Style="{StaticResource RoundedTextBox}"/>
|
||||||
|
@ -126,130 +132,214 @@
|
||||||
Margin="5,0"
|
Margin="5,0"
|
||||||
Style="{StaticResource ButtonStyle}"
|
Style="{StaticResource ButtonStyle}"
|
||||||
Click="VideoPathBrowseButton_Click"/>
|
Click="VideoPathBrowseButton_Click"/>
|
||||||
|
<Button Content="Open"
|
||||||
|
Width="75"
|
||||||
|
Height="30"
|
||||||
|
FontFamily="{StaticResource Orbitron}"
|
||||||
|
Margin="5,0"
|
||||||
|
Style="{StaticResource ButtonStyle}"
|
||||||
|
Click="VideoPathOpenButton_Click"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Toggle Settings Grid -->
|
<!-- Toggle Settings Grid -->
|
||||||
<Grid Margin="0,0,0,10">
|
<Grid Margin="0,0,0,10">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Visor Wipe Toggle -->
|
<!-- Left Column Controls -->
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Video Record Toggle -->
|
<!-- Visor Wipe Toggle -->
|
||||||
<StackPanel Grid.Column="1" Grid.Row="0"
|
<StackPanel Grid.Column="0"
|
||||||
Orientation="Horizontal"
|
Grid.Row="0"
|
||||||
Margin="5,0,0,5">
|
Orientation="Horizontal"
|
||||||
<TextBlock Text="ⓘ"
|
Margin="0,0,5,5">
|
||||||
ToolTip="Automatically clip your last kill. Check the README for more info."
|
<TextBlock Text="ⓘ"
|
||||||
Foreground="{DynamicResource TextBrush}"
|
ToolTip="Perform a Visor Wipe animation on player kill. Requires AHKv2."
|
||||||
FontSize="20"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
Margin="0,4,3,0"/>
|
FontSize="20"
|
||||||
<TextBlock Text="Video Record:"
|
Margin="0,4,3,0"/>
|
||||||
Foreground="{DynamicResource TextBrush}"
|
<TextBlock Text="Visor Wipe:"
|
||||||
FontSize="16"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
Margin="0,7,0,0"/>
|
FontSize="16"
|
||||||
<Slider Name="VideoRecordSlider"
|
Margin="0,7,0,0"/>
|
||||||
Minimum="0"
|
<Slider Name="VisorWipeSlider"
|
||||||
Maximum="1"
|
Minimum="0"
|
||||||
TickFrequency="1"
|
Maximum="1"
|
||||||
IsSnapToTickEnabled="True"
|
TickFrequency="1"
|
||||||
Value="0"
|
IsSnapToTickEnabled="True"
|
||||||
Style="{StaticResource ToggleSliderStyle}"
|
Value="0"
|
||||||
Margin="10,-4,0,0"
|
Style="{StaticResource ToggleSliderStyle}"
|
||||||
Width="100"
|
Margin="10,-4,0,0"
|
||||||
ValueChanged="VideoRecordSlider_ValueChanged"/>
|
Width="100"
|
||||||
</StackPanel>
|
ValueChanged="VisorWipeSlider_ValueChanged"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Offline Mode Toggle -->
|
<!-- Video Record Toggle -->
|
||||||
<StackPanel Grid.Column="0" Grid.Row="1"
|
<StackPanel Grid.Column="0"
|
||||||
Orientation="Horizontal"
|
Grid.Row="1"
|
||||||
Margin="0,0,5,5">
|
Orientation="Horizontal"
|
||||||
<TextBlock Text="ⓘ"
|
Margin="0,0,5,5">
|
||||||
ToolTip="With Offline Mode enabled, kills will not be submitted to the configured API."
|
<TextBlock Text="ⓘ"
|
||||||
Foreground="{DynamicResource TextBrush}"
|
ToolTip="Record video on player kill. Requires AHKv2."
|
||||||
FontSize="20"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
Margin="0,4,3,0"/>
|
FontSize="20"
|
||||||
<TextBlock Text="Offline Mode:"
|
Margin="0,4,3,0"/>
|
||||||
Foreground="{DynamicResource TextBrush}"
|
<TextBlock Text="Video Record:"
|
||||||
FontSize="16"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
Margin="0,7,0,0"/>
|
FontSize="16"
|
||||||
<Slider Name="OfflineModeSlider"
|
Margin="0,7,0,0"/>
|
||||||
Minimum="0"
|
<Slider Name="VideoRecordSlider"
|
||||||
Maximum="1"
|
Minimum="0"
|
||||||
TickFrequency="1"
|
Maximum="1"
|
||||||
IsSnapToTickEnabled="True"
|
TickFrequency="1"
|
||||||
Value="0"
|
IsSnapToTickEnabled="True"
|
||||||
Style="{StaticResource ToggleSliderStyle}"
|
Value="0"
|
||||||
Margin="10,-4,0,0"
|
Style="{StaticResource ToggleSliderStyle}"
|
||||||
Width="100"
|
Margin="10,-4,0,0"
|
||||||
ValueChanged="OfflineModeSlider_ValueChanged"/>
|
Width="100"
|
||||||
</StackPanel>
|
ValueChanged="VideoRecordSlider_ValueChanged"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Theme Slider -->
|
<!-- Offline Mode Toggle -->
|
||||||
<StackPanel Grid.Column="0" Grid.Row="2"
|
<StackPanel Grid.Column="0"
|
||||||
Grid.ColumnSpan="2"
|
Grid.Row="2"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Margin="0,0,0,5">
|
Margin="0,0,5,5">
|
||||||
<TextBlock Text="Theme:"
|
<TextBlock Text="ⓘ"
|
||||||
Foreground="{DynamicResource TextBrush}"
|
ToolTip="With Offline Mode enabled, kills will not be submitted to the configured API."
|
||||||
FontSize="16"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
Margin="0,7,10,0"/>
|
FontSize="20"
|
||||||
<Slider x:Name="ThemeSlider"
|
Margin="0,4,3,0"/>
|
||||||
Minimum="0"
|
<TextBlock Text="Offline Mode:"
|
||||||
Value="0"
|
Foreground="{DynamicResource TextBrush}"
|
||||||
TickFrequency="1"
|
FontSize="16"
|
||||||
IsSnapToTickEnabled="True"
|
Margin="0,7,0,0"/>
|
||||||
ValueChanged="ThemeSlider_ValueChanged"
|
<Slider Name="OfflineModeSlider"
|
||||||
Width="447"
|
Minimum="0"
|
||||||
Style="{StaticResource ThreePositionSlider}"/>
|
Maximum="1"
|
||||||
</StackPanel>
|
TickFrequency="1"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
Value="0"
|
||||||
|
Style="{StaticResource ToggleSliderStyle}"
|
||||||
|
Margin="10,-4,0,0"
|
||||||
|
Width="100"
|
||||||
|
ValueChanged="OfflineModeSlider_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>
|
||||||
|
|
||||||
|
<!-- 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>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- Save Button -->
|
<!-- Save Button -->
|
||||||
<StackPanel Grid.Column="2"
|
<Button x:Name="SaveButton"
|
||||||
HorizontalAlignment="Right"
|
Grid.Row="1"
|
||||||
VerticalAlignment="Bottom"
|
Content="Save"
|
||||||
Margin="0,0,0,10">
|
Width="100"
|
||||||
<Button x:Name="SaveButton"
|
Height="40"
|
||||||
Content="Save"
|
Style="{StaticResource ButtonStyle}"
|
||||||
Width="100"
|
FontFamily="{StaticResource Orbitron}"
|
||||||
Height="40"
|
HorizontalAlignment="Right"
|
||||||
Style="{StaticResource ButtonStyle}"
|
VerticalAlignment="Bottom"
|
||||||
FontFamily="{StaticResource Orbitron}"
|
Margin="0,0,80,20"
|
||||||
Click="SaveButton_Click"/>
|
Click="SaveButton_Click"/>
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
|
@ -11,6 +11,7 @@ using System.Windows.Media;
|
||||||
using System.Windows.Media.Effects;
|
using System.Windows.Media.Effects;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace AutoTrackR2;
|
namespace AutoTrackR2;
|
||||||
|
|
||||||
|
@ -36,6 +37,18 @@ public partial class ConfigPage : UserControl
|
||||||
VideoRecordSlider.Value = ConfigManager.VideoRecord;
|
VideoRecordSlider.Value = ConfigManager.VideoRecord;
|
||||||
OfflineModeSlider.Value = ConfigManager.OfflineMode;
|
OfflineModeSlider.Value = ConfigManager.OfflineMode;
|
||||||
ThemeSlider.Value = ConfigManager.Theme;
|
ThemeSlider.Value = ConfigManager.Theme;
|
||||||
|
StreamlinkSlider.Value = ConfigManager.StreamlinkEnabled;
|
||||||
|
StreamlinkDurationSlider.Value = ConfigManager.StreamlinkDuration;
|
||||||
|
|
||||||
|
// Initialize Streamlink slider style
|
||||||
|
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);
|
ApplyToggleModeStyle(OfflineModeSlider.Value, VisorWipeSlider.Value, VideoRecordSlider.Value);
|
||||||
|
|
||||||
|
@ -213,51 +226,6 @@ public partial class ConfigPage : UserControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VisorWipeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
|
||||||
{
|
|
||||||
Slider slider = (Slider)sender;
|
|
||||||
|
|
||||||
// Build the dynamic file path for the current user
|
|
||||||
if (string.IsNullOrEmpty(ConfigManager.AHKScriptFolder))
|
|
||||||
{
|
|
||||||
MessageBox.Show("AHK script folder path is not configured.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
string filePath = Path.Combine(
|
|
||||||
ConfigManager.AHKScriptFolder,
|
|
||||||
"visorwipe.ahk"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get the current value of the slider (0 or 1)
|
|
||||||
ConfigManager.VisorWipe = (int)slider.Value;
|
|
||||||
|
|
||||||
if (ConfigManager.VisorWipe == 1)
|
|
||||||
{
|
|
||||||
// Check if the file exists
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
// Apply the enabled style if the file exists
|
|
||||||
slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// File does not exist; revert the toggle to 0
|
|
||||||
ConfigManager.VisorWipe = 0;
|
|
||||||
slider.Value = 0; // Revert the slider value
|
|
||||||
slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle");
|
|
||||||
|
|
||||||
// Optionally, display a message to the user
|
|
||||||
MessageBox.Show($"Visor wipe script not found. Please ensure the file exists at:\n{filePath}",
|
|
||||||
"File Missing", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Apply the disabled style
|
|
||||||
slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void VideoRecordSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
private void VideoRecordSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||||
{
|
{
|
||||||
Slider slider = (Slider)sender;
|
Slider slider = (Slider)sender;
|
||||||
|
@ -315,6 +283,51 @@ public partial class ConfigPage : UserControl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void VisorWipeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||||
|
{
|
||||||
|
Slider slider = (Slider)sender;
|
||||||
|
|
||||||
|
// Build the dynamic file path for the current user
|
||||||
|
if (string.IsNullOrEmpty(ConfigManager.AHKScriptFolder))
|
||||||
|
{
|
||||||
|
MessageBox.Show("AHK script folder path is not configured.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string filePath = Path.Combine(
|
||||||
|
ConfigManager.AHKScriptFolder,
|
||||||
|
"visorwipe.ahk"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the current value of the slider (0 or 1)
|
||||||
|
ConfigManager.VisorWipe = (int)slider.Value;
|
||||||
|
|
||||||
|
if (ConfigManager.VisorWipe == 1)
|
||||||
|
{
|
||||||
|
// Check if the file exists
|
||||||
|
if (File.Exists(filePath))
|
||||||
|
{
|
||||||
|
// Apply the enabled style if the file exists
|
||||||
|
slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// File does not exist; revert the toggle to 0
|
||||||
|
ConfigManager.VisorWipe = 0;
|
||||||
|
slider.Value = 0; // Revert the slider value
|
||||||
|
slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle");
|
||||||
|
|
||||||
|
// Optionally, display a message to the user
|
||||||
|
MessageBox.Show($"Visor wipe script not found. Please ensure the file exists at:\n{filePath}",
|
||||||
|
"File Missing", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply the disabled style
|
||||||
|
slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void SaveButton_Click(object sender, RoutedEventArgs e)
|
private void SaveButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ConfigManager.ApiKey = ApiKey.Password;
|
ConfigManager.ApiKey = ApiKey.Password;
|
||||||
|
@ -422,6 +435,133 @@ public partial class ConfigPage : UserControl
|
||||||
MessageBox.Show($"API Test Failure. {ex.Message}");
|
MessageBox.Show($"API Test Failure. {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (slider.Value == 0)
|
||||||
|
{
|
||||||
|
slider.Style = (Style)Application.Current.FindResource("FalseToggleStyle");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slider.Style = (Style)Application.Current.FindResource("ToggleSliderStyle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StreamlinkDurationSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||||
|
{
|
||||||
|
if (StreamlinkDurationText != null)
|
||||||
|
{
|
||||||
|
int duration = (int)e.NewValue;
|
||||||
|
StreamlinkDurationText.Text = $"{duration}s";
|
||||||
|
ConfigManager.StreamlinkDuration = duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void TestStreamlinkButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("TestStreamlinkButton_Click: Starting streamlink test");
|
||||||
|
|
||||||
|
if (ConfigManager.StreamlinkEnabled != 1)
|
||||||
|
{
|
||||||
|
Debug.WriteLine("TestStreamlinkButton_Click: Streamlink is not enabled");
|
||||||
|
MessageBox.Show("Streamlink is not enabled. Please enable Streamlink to test.", "Error", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Debug.WriteLine("TestStreamlinkButton_Click: Configuring HTTP client");
|
||||||
|
// Configure HttpClient with TLS 1.2
|
||||||
|
var handler = new HttpClientHandler
|
||||||
|
{
|
||||||
|
SslProtocols = System.Security.Authentication.SslProtocols.Tls12
|
||||||
|
};
|
||||||
|
|
||||||
|
using (var client = new HttpClient(handler))
|
||||||
|
{
|
||||||
|
// Set headers
|
||||||
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", ConfigManager.ApiKey);
|
||||||
|
client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR2");
|
||||||
|
|
||||||
|
// Create JSON body with version
|
||||||
|
var jsonBody = new { version = "2.10" };
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(jsonBody), Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
// Send POST to test endpoint
|
||||||
|
string baseUrl = Regex.Replace(ConfigManager.ApiUrl ?? "", @"(https?://[^/]+)/?.*", "$1");
|
||||||
|
string endpoint = "test";
|
||||||
|
string fullUrl = $"{baseUrl}/{endpoint}";
|
||||||
|
Debug.WriteLine($"TestStreamlinkButton_Click: Sending request to {fullUrl}");
|
||||||
|
|
||||||
|
var response = await client.PostAsync(fullUrl, content);
|
||||||
|
Debug.WriteLine($"TestStreamlinkButton_Click: Response status code: {response.StatusCode}");
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
Debug.WriteLine($"TestStreamlinkButton_Click: Response content: {responseContent}");
|
||||||
|
WebHandler.ProcessStreamerResponse(responseContent);
|
||||||
|
MessageBox.Show("Streamlink Test Success.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"TestStreamlinkButton_Click: Error response: {response.StatusCode} - {response.ReasonPhrase}");
|
||||||
|
MessageBox.Show($"Error: {response.StatusCode} - {response.ReasonPhrase}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"TestStreamlinkButton_Click: Exception: {ex.Message}");
|
||||||
|
MessageBox.Show($"Streamlink Test Failure. {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
public class Theme
|
||||||
|
|
|
@ -196,6 +196,8 @@ namespace AutoTrackR2
|
||||||
public static int VideoRecord { get; set; }
|
public static int VideoRecord { get; set; }
|
||||||
public static int OfflineMode { get; set; }
|
public static int OfflineMode { get; set; }
|
||||||
public static int Theme { get; set; }
|
public static int Theme { get; set; }
|
||||||
|
public static int StreamlinkEnabled { get; set; }
|
||||||
|
public static int StreamlinkDuration { get; set; } = 30;
|
||||||
|
|
||||||
static ConfigManager()
|
static ConfigManager()
|
||||||
{
|
{
|
||||||
|
@ -247,6 +249,10 @@ namespace AutoTrackR2
|
||||||
OfflineMode = int.Parse(line.Substring("OfflineMode=".Length).Trim());
|
OfflineMode = int.Parse(line.Substring("OfflineMode=".Length).Trim());
|
||||||
else if (line.StartsWith("Theme="))
|
else if (line.StartsWith("Theme="))
|
||||||
Theme = int.Parse(line.Substring("Theme=".Length).Trim());
|
Theme = int.Parse(line.Substring("Theme=".Length).Trim());
|
||||||
|
else if (line.StartsWith("StreamlinkEnabled="))
|
||||||
|
StreamlinkEnabled = int.Parse(line.Substring("StreamlinkEnabled=".Length).Trim());
|
||||||
|
else if (line.StartsWith("StreamlinkDuration="))
|
||||||
|
StreamlinkDuration = int.Parse(line.Substring("StreamlinkDuration=".Length).Trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,6 +284,8 @@ namespace AutoTrackR2
|
||||||
writer.WriteLine($"VideoRecord={VideoRecord}");
|
writer.WriteLine($"VideoRecord={VideoRecord}");
|
||||||
writer.WriteLine($"OfflineMode={OfflineMode}");
|
writer.WriteLine($"OfflineMode={OfflineMode}");
|
||||||
writer.WriteLine($"Theme={Theme}");
|
writer.WriteLine($"Theme={Theme}");
|
||||||
|
writer.WriteLine($"StreamlinkEnabled={StreamlinkEnabled}");
|
||||||
|
writer.WriteLine($"StreamlinkDuration={StreamlinkDuration}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
88
AutoTrackR2/StreamlinkHandler.cs
Normal file
88
AutoTrackR2/StreamlinkHandler.cs
Normal file
|
@ -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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,4 +54,11 @@ public static class TrackREventDispatcher
|
||||||
{
|
{
|
||||||
JumpDriveStateChangedEvent?.Invoke(data);
|
JumpDriveStateChangedEvent?.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static event Action<string>? StreamlinkRecordEvent;
|
||||||
|
|
||||||
|
public static void OnStreamlinkRecordEvent(string streamerHandle)
|
||||||
|
{
|
||||||
|
StreamlinkRecordEvent?.Invoke(streamerHandle);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -155,7 +155,12 @@ public static class WebHandler
|
||||||
Console.WriteLine($"Time (UTC): {DateTimeOffset.UtcNow}");
|
Console.WriteLine($"Time (UTC): {DateTimeOffset.UtcNow}");
|
||||||
Console.WriteLine("=== End Debug Info ===\n");
|
Console.WriteLine("=== End Debug Info ===\n");
|
||||||
|
|
||||||
var response = await httpClient.PostAsync(ConfigManager.ApiUrl + "register-kill", new StringContent(jsonData, Encoding.UTF8, "application/json"));
|
// Ensure proper URL formatting
|
||||||
|
string baseUrl = Regex.Replace(ConfigManager.ApiUrl ?? "", @"(https?://[^/]+)/?.*", "$1");
|
||||||
|
string endpoint = "register-kill";
|
||||||
|
string fullUrl = $"{baseUrl}/{endpoint}";
|
||||||
|
|
||||||
|
var response = await httpClient.PostAsync(fullUrl, new StringContent(jsonData, Encoding.UTF8, "application/json"));
|
||||||
if (response.StatusCode != HttpStatusCode.OK)
|
if (response.StatusCode != HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to submit kill data:");
|
Console.WriteLine("Failed to submit kill data:");
|
||||||
|
@ -167,7 +172,50 @@ public static class WebHandler
|
||||||
else if (response.StatusCode == HttpStatusCode.OK)
|
else if (response.StatusCode == HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Successfully submitted kill data");
|
Console.WriteLine("Successfully submitted kill data");
|
||||||
Console.WriteLine($"Response: {await response.Content.ReadAsStringAsync()}");
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
Console.WriteLine($"Response: {responseContent}");
|
||||||
|
|
||||||
|
// Only process streamer data if streamlink is enabled
|
||||||
|
if (ConfigManager.StreamlinkEnabled == 1)
|
||||||
|
{
|
||||||
|
ProcessStreamerResponse(responseContent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ProcessStreamerResponse(string responseContent)
|
||||||
|
{
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
// Sanitize the streamer handle before using it, this is to prevent any malicious instructions.
|
||||||
|
string sanitizedHandle = SanitizeStreamerHandle(streamerHandle);
|
||||||
|
if (!string.IsNullOrEmpty(sanitizedHandle))
|
||||||
|
{
|
||||||
|
TrackREventDispatcher.OnStreamlinkRecordEvent(sanitizedHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error parsing streamer from response: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string SanitizeStreamerHandle(string handle)
|
||||||
|
{
|
||||||
|
// Twitch usernames 4-25 characters, letters, numbers and underscores.
|
||||||
|
if (Regex.IsMatch(handle, @"^[a-zA-Z0-9_]{4,25}$"))
|
||||||
|
{
|
||||||
|
return handle.ToLower(); // Api won't return anything other than lowercase but just in case.
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty; // Reject invalid handles
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -6,3 +6,4 @@ VisorWipe=0
|
||||||
VideoRecord=0
|
VideoRecord=0
|
||||||
OfflineMode=0
|
OfflineMode=0
|
||||||
Theme=0
|
Theme=0
|
||||||
|
StreamlinkEnabled=0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue