66using System . Drawing ;
77using System . IO ;
88using System . Linq ;
9+ using System . Net . Http ;
910using System . Text ;
11+ using System . Text . Json ;
1012using System . Threading . Tasks ;
1113using System . Windows . Forms ;
1214
@@ -15,13 +17,24 @@ namespace VDD_Control
1517 public partial class CommunityScriptsForm : Form
1618 {
1719 private const string SCRIPTS_FOLDER = "Community Scripts" ;
20+ private const string GITHUB_SCRIPTS_URL = "https://github.com/VirtualDrivers/Virtual-Display-Driver/tree/master/Community%20Scripts" ;
1821 private ListBox scriptListBox ;
1922 private Label noScriptsLabel ;
23+ private Button syncButton ;
2024
2125 public CommunityScriptsForm ( )
2226 {
2327 InitializeComponents ( ) ;
2428 LoadScripts ( ) ;
29+
30+ // Handle resize to keep button visible
31+ this . Resize += CommunityScriptsForm_Resize ;
32+ }
33+
34+ private void CommunityScriptsForm_Resize ( object sender , EventArgs e )
35+ {
36+ // Ensure controls are properly laid out after resize
37+ this . PerformLayout ( ) ;
2538 }
2639
2740 private void InitializeComponents ( )
@@ -36,6 +49,22 @@ private void InitializeComponents()
3649 this . BackColor = Color . FromArgb ( 32 , 34 , 37 ) ;
3750 this . ForeColor = Color . White ;
3851
52+ // Set up the form layout
53+ this . Controls . Clear ( ) ;
54+
55+ // Create TableLayoutPanel for better control of layout
56+ TableLayoutPanel tableLayout = new TableLayoutPanel
57+ {
58+ Dock = DockStyle . Fill ,
59+ RowCount = 2 ,
60+ ColumnCount = 1 ,
61+ Padding = new Padding ( 10 , 10 , 10 , 10 )
62+ } ;
63+
64+ // Configure rows - first row (scripts) takes all available space, second row (button) is fixed height
65+ tableLayout . RowStyles . Add ( new RowStyle ( SizeType . Percent , 100F ) ) ;
66+ tableLayout . RowStyles . Add ( new RowStyle ( SizeType . Absolute , 40F ) ) ;
67+
3968 // Create script list box
4069 scriptListBox = new ListBox
4170 {
@@ -57,9 +86,32 @@ private void InitializeComponents()
5786 Visible = false
5887 } ;
5988
60- // Add controls to form
61- this . Controls . Add ( scriptListBox ) ;
62- this . Controls . Add ( noScriptsLabel ) ;
89+ // Create sync button
90+ syncButton = new Button
91+ {
92+ Text = "Sync from GitHub" ,
93+ BackColor = Color . FromArgb ( 114 , 137 , 218 ) ,
94+ ForeColor = Color . White ,
95+ FlatStyle = FlatStyle . Flat ,
96+ Dock = DockStyle . Fill ,
97+ Margin = new Padding ( 0 , 5 , 0 , 0 )
98+ } ;
99+ syncButton . Click += SyncButton_Click ;
100+
101+ // Panel to hold the list or label
102+ Panel listPanel = new Panel
103+ {
104+ Dock = DockStyle . Fill
105+ } ;
106+ listPanel . Controls . Add ( scriptListBox ) ;
107+ listPanel . Controls . Add ( noScriptsLabel ) ;
108+
109+ // Add controls to the table layout
110+ tableLayout . Controls . Add ( listPanel , 0 , 0 ) ;
111+ tableLayout . Controls . Add ( syncButton , 0 , 1 ) ;
112+
113+ // Add the layout to the form
114+ this . Controls . Add ( tableLayout ) ;
63115 }
64116
65117 private void LoadScripts ( )
@@ -166,5 +218,87 @@ public void RefreshScripts()
166218 {
167219 LoadScripts ( ) ;
168220 }
221+
222+ private async void SyncButton_Click ( object sender , EventArgs e )
223+ {
224+ // Disable the sync button during the operation
225+ syncButton . Enabled = false ;
226+ syncButton . Text = "Syncing..." ;
227+
228+ try
229+ {
230+ await SyncScriptsFromGitHub ( ) ;
231+ MessageBox . Show ( "Community scripts successfully synchronized from GitHub!" ,
232+ "Sync Complete" , MessageBoxButtons . OK , MessageBoxIcon . Information ) ;
233+ }
234+ catch ( Exception ex )
235+ {
236+ MessageBox . Show ( $ "Error synchronizing scripts: { ex . Message } ",
237+ "Sync Error" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
238+ }
239+ finally
240+ {
241+ // Re-enable the button
242+ syncButton . Enabled = true ;
243+ syncButton . Text = "Sync from GitHub" ;
244+
245+ // Refresh the script list to show the updates
246+ LoadScripts ( ) ;
247+ }
248+ }
249+
250+ private async Task SyncScriptsFromGitHub ( )
251+ {
252+ // Create HTTP client
253+ using ( HttpClient client = new HttpClient ( ) )
254+ {
255+ // GitHub API requires a user agent
256+ client . DefaultRequestHeaders . Add ( "User-Agent" , "VDD-Control-App" ) ;
257+
258+ // Convert the GitHub web URL to API URL to get the directory contents
259+ // Format: https://api.github.com/repos/{owner}/{repo}/contents/{path}
260+ string apiUrl = "https://api.github.com/repos/VirtualDrivers/Virtual-Display-Driver/contents/Community%20Scripts" ;
261+
262+ // Get the directory listing
263+ HttpResponseMessage response = await client . GetAsync ( apiUrl ) ;
264+ response . EnsureSuccessStatusCode ( ) ;
265+
266+ string responseBody = await response . Content . ReadAsStringAsync ( ) ;
267+ JsonDocument doc = JsonDocument . Parse ( responseBody ) ;
268+
269+ // Make sure the scripts directory exists
270+ string scriptsDirectory = Path . Combine ( AppDomain . CurrentDomain . BaseDirectory , SCRIPTS_FOLDER ) ;
271+ if ( ! Directory . Exists ( scriptsDirectory ) )
272+ {
273+ Directory . CreateDirectory ( scriptsDirectory ) ;
274+ }
275+
276+ // Process each file in the repository
277+ foreach ( JsonElement item in doc . RootElement . EnumerateArray ( ) )
278+ {
279+ // Only download script files (.cmd, .bat, .ps1, .exe)
280+ string fileName = item . GetProperty ( "name" ) . GetString ( ) ;
281+ if ( fileName . EndsWith ( ".cmd" , StringComparison . OrdinalIgnoreCase ) ||
282+ fileName . EndsWith ( ".bat" , StringComparison . OrdinalIgnoreCase ) ||
283+ fileName . EndsWith ( ".ps1" , StringComparison . OrdinalIgnoreCase ) ||
284+ fileName . EndsWith ( ".exe" , StringComparison . OrdinalIgnoreCase ) )
285+ {
286+ // Get download URL
287+ string downloadUrl = item . GetProperty ( "download_url" ) . GetString ( ) ;
288+
289+ // Download the file
290+ HttpResponseMessage fileResponse = await client . GetAsync ( downloadUrl ) ;
291+ fileResponse . EnsureSuccessStatusCode ( ) ;
292+
293+ // Save the file to the scripts directory
294+ string filePath = Path . Combine ( scriptsDirectory , fileName ) ;
295+ using ( FileStream fs = new FileStream ( filePath , FileMode . Create ) )
296+ {
297+ await fileResponse . Content . CopyToAsync ( fs ) ;
298+ }
299+ }
300+ }
301+ }
302+ }
169303 }
170304}
0 commit comments