-
Notifications
You must be signed in to change notification settings - Fork 44
/
Downloader.cs
147 lines (133 loc) · 5.13 KB
/
Downloader.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using DotNetTools.SharpGrabber.Converter;
using DotNetTools.SharpGrabber.Media;
using SharpGrabber.Desktop.ViewModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace SharpGrabber.Desktop
{
public class Downloader
{
#region Fields
private GrabbedMediaViewModel _viewModel;
private string _targetPath;
#endregion
#region Constructors
public Downloader(GrabbedMediaViewModel grabbedViewModel, string targetPath)
{
_viewModel = grabbedViewModel;
_targetPath = targetPath;
}
#endregion
#region Internal Methods
private async Task SingleDownload(Uri uri, Stream outputStream, string downloadingText = "Downloading {0}...")
{
using (var client = new HttpClient())
using (var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength;
if (totalBytes == 0)
throw new Exception("No data to download.");
else
_viewModel.DownloadStatus = string.Format(downloadingText, UIHelpers.BytesToString(totalBytes.Value));
var remainingBytes = totalBytes;
var lastProgress = double.MinValue;
using (var stream = await response.Content.ReadAsStreamAsync())
{
var buffer = new byte[4096];
while (true)
{
var countToRead = (int)Math.Min(remainingBytes ?? int.MaxValue, buffer.Length);
var read = await stream.ReadAsync(buffer, 0, countToRead);
if (read <= 0)
break;
await outputStream.WriteAsync(buffer, 0, read);
if (totalBytes.HasValue)
{
remainingBytes -= read;
var progress = (totalBytes.Value - remainingBytes.Value) / (double)totalBytes.Value;
if (Math.Abs(progress - lastProgress) > 0.005)
{
_viewModel.DownloadProgress = progress;
lastProgress = progress;
}
}
}
_viewModel.DownloadProgress = 1;
}
}
}
private async Task SingleDownload(Uri uri, string outputPath, string downloadingText = "Downloading {0}...")
{
try
{
using (var outputStream = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.None))
await SingleDownload(uri, outputStream, downloadingText);
}
catch (Exception)
{
File.Delete(outputPath);
throw;
}
}
private async Task CompositeDownload()
{
var audioPath = IOHelper.GenerateTempPath();
var videoPath = IOHelper.GenerateTempPath();
var streamPaths = new[] { audioPath, videoPath };
var videoStream = _viewModel.Media;
var audioStream = _viewModel.AttachTo;
try
{
_viewModel.DownloadStatus = "Preparing download...";
await SingleDownload(videoStream.ResourceUri, videoPath, "Downloading video stream {0}...");
await SingleDownload(audioStream.ResourceUri, audioPath, "Downloading audio stream {0}...");
_viewModel.DownloadProgress = 0;
_viewModel.DownloadStatus = "Composing output media...";
await Task.Run(() =>
{
ConvertHelper.Convert(videoStream, audioStream, videoPath, audioPath, _targetPath);
});
}
finally
{
foreach (var path in streamPaths)
if (File.Exists(path))
File.Delete(path);
}
}
#endregion
#region Methods
public async Task Download()
{
// init
var media = _viewModel.Media;
_viewModel.IsDownloading = true;
_viewModel.DownloadStatus = "Initializing...";
_viewModel.DownloadPercent = 0;
try
{
// is composite download?
if (_viewModel.IsComposition)
{
// Composed download
await CompositeDownload();
return;
}
// single download
_viewModel.DownloadStatus = "Downloading...";
await SingleDownload(media.ResourceUri, _targetPath);
}
finally
{
_viewModel.IsDownloading = false;
}
}
#endregion
}
}