Skip to content

Commit 8f17dc9

Browse files
committed
⛷️ Refactor backend output handling
Read from stdout and stderr streams directly, instead of registering event handlers.
1 parent add110e commit 8f17dc9

File tree

5 files changed

+66
-75
lines changed

5 files changed

+66
-75
lines changed

YoutubeDl.Wpf/Models/BackendInstance.cs

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System.Globalization;
99
using System.IO;
1010
using System.Linq;
11-
using System.Reactive.Concurrency;
1211
using System.Text;
1312
using System.Threading;
1413
using System.Threading.Tasks;
@@ -64,19 +63,49 @@ public BackendInstance(ObservableSettings settings, BackendService backendServic
6463
_dlProcess.StartInfo.StandardErrorEncoding = Encoding.UTF8;
6564
_dlProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;
6665
_dlProcess.EnableRaisingEvents = true;
67-
_dlProcess.ErrorDataReceived += DlOutputHandler;
68-
_dlProcess.OutputDataReceived += DlOutputHandler;
69-
_dlProcess.Exited += DlProcess_Exited;
7066
}
7167

72-
private void DlOutputHandler(object? sendingProcess, DataReceivedEventArgs outLine)
68+
private async Task RunDlAsync(CancellationToken cancellationToken = default)
7369
{
74-
if (outLine.Data is null)
75-
return;
70+
if (!_dlProcess.Start())
71+
throw new InvalidOperationException("Method called when the backend process is running.");
7672

77-
this.Log().Info(outLine.Data);
73+
SetStatusRunning();
7874

79-
RxApp.MainThreadScheduler.Schedule(() => ParseDlOutput(outLine.Data));
75+
await Task.WhenAll(
76+
ReadAndParseAsync(_dlProcess.StandardError, cancellationToken),
77+
ReadAndParseAsync(_dlProcess.StandardOutput, cancellationToken),
78+
_dlProcess.WaitForExitAsync(cancellationToken));
79+
80+
SetStatusStopped();
81+
}
82+
83+
private void SetStatusRunning()
84+
{
85+
StatusIndeterminate = true;
86+
IsRunning = true;
87+
_backendService.UpdateProgress();
88+
}
89+
90+
private void SetStatusStopped()
91+
{
92+
DownloadProgressPercentage = 0.0;
93+
StatusIndeterminate = false;
94+
IsRunning = false;
95+
_backendService.UpdateProgress();
96+
}
97+
98+
private async Task ReadAndParseAsync(StreamReader reader, CancellationToken cancellationToken = default)
99+
{
100+
while (true)
101+
{
102+
var line = await reader.ReadLineAsync(cancellationToken);
103+
if (line is null)
104+
return;
105+
106+
this.Log().Info(line);
107+
ParseDlOutput(line);
108+
}
80109
}
81110

82111
private void ParseDlOutput(string output)
@@ -106,20 +135,6 @@ private void ParseDlOutput(string output)
106135
}
107136
}
108137

109-
private void DlProcess_Exited(object? sender, EventArgs e)
110-
{
111-
_dlProcess.CancelErrorRead();
112-
_dlProcess.CancelOutputRead();
113-
114-
RxApp.MainThreadScheduler.Schedule(() =>
115-
{
116-
DownloadProgressPercentage = 0.0;
117-
StatusIndeterminate = false;
118-
IsRunning = false;
119-
_backendService.UpdateProgress();
120-
});
121-
}
122-
123138
public void GenerateDownloadArguments()
124139
{
125140
GeneratedDownloadArguments.Clear();
@@ -231,7 +246,7 @@ public void GenerateDownloadArguments()
231246
}
232247
}
233248

234-
public void StartDownload(string link)
249+
public async Task StartDownloadAsync(string link, CancellationToken cancellationToken = default)
235250
{
236251
_dlProcess.StartInfo.FileName = _settings.BackendPath;
237252
_dlProcess.StartInfo.ArgumentList.Clear();
@@ -242,21 +257,15 @@ public void StartDownload(string link)
242257

243258
try
244259
{
245-
_dlProcess.Start();
246-
_dlProcess.BeginErrorReadLine();
247-
_dlProcess.BeginOutputReadLine();
248-
249-
StatusIndeterminate = true;
250-
IsRunning = true;
251-
_backendService.UpdateProgress();
260+
await RunDlAsync(cancellationToken);
252261
}
253262
catch (Exception ex)
254263
{
255264
this.Log().Error(ex);
256265
}
257266
}
258267

259-
public void ListFormats(string link)
268+
public async Task ListFormatsAsync(string link, CancellationToken cancellationToken = default)
260269
{
261270
_dlProcess.StartInfo.FileName = _settings.BackendPath;
262271
_dlProcess.StartInfo.ArgumentList.Clear();
@@ -271,21 +280,15 @@ public void ListFormats(string link)
271280

272281
try
273282
{
274-
_dlProcess.Start();
275-
_dlProcess.BeginErrorReadLine();
276-
_dlProcess.BeginOutputReadLine();
277-
278-
StatusIndeterminate = true;
279-
IsRunning = true;
280-
_backendService.UpdateProgress();
283+
await RunDlAsync(cancellationToken);
281284
}
282285
catch (Exception ex)
283286
{
284287
this.Log().Error(ex);
285288
}
286289
}
287290

288-
public async Task AbortDl(CancellationToken cancellationToken = default)
291+
public async Task AbortDlAsync(CancellationToken cancellationToken = default)
289292
{
290293
if (CtrlCHelper.AttachConsole((uint)_dlProcess.Id))
291294
{
@@ -310,7 +313,7 @@ public async Task AbortDl(CancellationToken cancellationToken = default)
310313
this.Log().Info("🛑 Aborted.");
311314
}
312315

313-
public void UpdateDl()
316+
public async Task UpdateDlAsync(CancellationToken cancellationToken = default)
314317
{
315318
_settings.BackendLastUpdateCheck = DateTimeOffset.Now;
316319

@@ -325,13 +328,7 @@ public void UpdateDl()
325328

326329
try
327330
{
328-
_dlProcess.Start();
329-
_dlProcess.BeginErrorReadLine();
330-
_dlProcess.BeginOutputReadLine();
331-
332-
StatusIndeterminate = true;
333-
IsRunning = true;
334-
_backendService.UpdateProgress();
331+
await RunDlAsync(cancellationToken);
335332
}
336333
catch (Exception ex)
337334
{

YoutubeDl.Wpf/Models/BackendService.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using Splat;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Threading;
7+
using System.Threading.Tasks;
68
using System.Windows.Shell;
79

810
namespace YoutubeDl.Wpf.Models;
@@ -51,14 +53,9 @@ public void UpdateProgress()
5153
}
5254
}
5355

54-
public void UpdateBackend()
56+
public Task UpdateBackendAsync(CancellationToken cancellationToken = default)
5557
{
56-
var instance = Instances.Count switch
57-
{
58-
> 0 => Instances[0],
59-
_ => new(_settings, this),
60-
};
61-
62-
instance.UpdateDl();
58+
var tasks = Instances.Select(x => x.UpdateDlAsync(cancellationToken));
59+
return Task.WhenAll(tasks);
6360
}
6461
}

YoutubeDl.Wpf/ViewModels/HomeViewModel.cs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ public class HomeViewModel : ReactiveValidationObject
5454
public ReactiveCommand<Unit, Unit> ResetCustomFilenameTemplateCommand { get; }
5555
public ReactiveCommand<Unit, Unit> BrowseDownloadFolderCommand { get; }
5656
public ReactiveCommand<Unit, Unit> OpenDownloadFolderCommand { get; }
57-
public ReactiveCommand<Unit, Unit> StartDownloadCommand { get; }
58-
public ReactiveCommand<Unit, Unit> ListFormatsCommand { get; }
57+
public ReactiveCommand<string, Unit> StartDownloadCommand { get; }
58+
public ReactiveCommand<string, Unit> ListFormatsCommand { get; }
5959
public ReactiveCommand<Unit, Unit> AbortDlCommand { get; }
6060

6161
public ReactiveCommand<Unit, Unit> OpenAddCustomPresetDialogCommand { get; }
@@ -82,6 +82,11 @@ public HomeViewModel(ObservableSettings settings, BackendService backendService,
8282
14 => PackIconKind.Heart,
8383
_ => defaultIcon,
8484
},
85+
5 => today.Day switch
86+
{
87+
8 => PackIconKind.Cake,
88+
_ => defaultIcon,
89+
},
8590
10 => today.Day switch
8691
{
8792
31 => PackIconKind.Halloween,
@@ -182,9 +187,9 @@ public HomeViewModel(ObservableSettings settings, BackendService backendService,
182187
ResetCustomFilenameTemplateCommand = ReactiveCommand.Create(ResetCustomFilenameTemplate, canResetCustomFilenameTemplate);
183188
BrowseDownloadFolderCommand = ReactiveCommand.Create(BrowseDownloadFolder, canBrowseDownloadFolder);
184189
OpenDownloadFolderCommand = ReactiveCommand.Create(OpenDownloadFolder, canOpenDownloadFolder);
185-
StartDownloadCommand = ReactiveCommand.Create(StartDownload, canStartDl);
186-
ListFormatsCommand = ReactiveCommand.Create(ListFormats, canStartDl);
187-
AbortDlCommand = ReactiveCommand.CreateFromTask(BackendInstance.AbortDl, canAbortDl);
190+
StartDownloadCommand = ReactiveCommand.CreateFromTask<string>(BackendInstance.StartDownloadAsync, canStartDl);
191+
ListFormatsCommand = ReactiveCommand.CreateFromTask<string>(BackendInstance.ListFormatsAsync, canStartDl);
192+
AbortDlCommand = ReactiveCommand.CreateFromTask(BackendInstance.AbortDlAsync, canAbortDl);
188193

189194
OpenAddCustomPresetDialogCommand = ReactiveCommand.Create(OpenAddCustomPresetDialog);
190195
OpenEditCustomPresetDialogCommand = ReactiveCommand.Create(OpenEditCustomPresetDialog, canEditOrDeletePreset);
@@ -193,7 +198,7 @@ public HomeViewModel(ObservableSettings settings, BackendService backendService,
193198

194199
if (SharedSettings.BackendAutoUpdate && !string.IsNullOrEmpty(SharedSettings.BackendPath))
195200
{
196-
BackendInstance.UpdateDl();
201+
_ = BackendInstance.UpdateDlAsync();
197202
}
198203
}
199204

@@ -273,16 +278,6 @@ private void ResetCustomFilenameTemplate()
273278
SharedSettings.CustomOutputTemplate = Settings.DefaultCustomFilenameTemplate;
274279
}
275280

276-
private void StartDownload()
277-
{
278-
BackendInstance.StartDownload(Link);
279-
}
280-
281-
private void ListFormats()
282-
{
283-
BackendInstance.ListFormats(Link);
284-
}
285-
286281
private void BrowseDownloadFolder()
287282
{
288283
Microsoft.Win32.OpenFileDialog folderDialog = new()

YoutubeDl.Wpf/ViewModels/SettingsViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public SettingsViewModel(ObservableSettings settings, BackendService backendServ
121121

122122
ChangeColorModeCommand = ReactiveCommand.Create<BaseTheme>(ChangeColorMode);
123123
BrowseDlBinaryCommand = ReactiveCommand.Create(BrowseDlBinary);
124-
UpdateBackendCommand = ReactiveCommand.Create(_backendService.UpdateBackend, canUpdateBackend);
124+
UpdateBackendCommand = ReactiveCommand.CreateFromTask(_backendService.UpdateBackendAsync, canUpdateBackend);
125125
BrowseFfmpegBinaryCommand = ReactiveCommand.Create(BrowseFfmpegBinary);
126126
OpenUri = ReactiveCommand.Create<string>(WpfHelper.OpenUri);
127127
}

YoutubeDl.Wpf/Views/HomeView.xaml.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,14 @@ public HomeView()
172172
// Download, list, abort button
173173
this.BindCommand(ViewModel,
174174
viewModel => viewModel.StartDownloadCommand,
175-
view => view.downloadButton)
175+
view => view.downloadButton,
176+
viewModel => viewModel.Link)
176177
.DisposeWith(disposables);
177178

178179
this.BindCommand(ViewModel,
179180
viewModel => viewModel.ListFormatsCommand,
180-
view => view.listFormatsButton)
181+
view => view.listFormatsButton,
182+
viewModel => viewModel.Link)
181183
.DisposeWith(disposables);
182184

183185
this.BindCommand(ViewModel,

0 commit comments

Comments
 (0)