public static async Task DownloadFile(string url, string path, bool aria2c) { LogDebug("Start downloading: {0}", url); if (aria2c) { BBDownAria2c.DownloadFileByAria2c(url, path); if (File.Exists(path + ".aria2") || !File.Exists(path)) { throw new Exception("aria2下载可能存在错误"); } Console.WriteLine(); return; } string tmpName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path) + ".tmp"); using (var progress = new ProgressBar()) { long totalLength = -1; WebClient client = new WebClient(); if (!url.Contains("platform=android_tv_yst")) { client.Headers.Add("Referer", "https://www.bilibili.com"); } client.Headers.Add("User-Agent", "Mozilla/5.0"); client.Headers.Add("Cookie", Program.COOKIE); client.Credentials = CredentialCache.DefaultCredentials; Uri uri = new Uri(url); client.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e) { if (totalLength == -1) { totalLength = e.TotalBytesToReceive; } progress.Report((double)e.BytesReceived / e.TotalBytesToReceive); }; await client.DownloadFileTaskAsync(uri, tmpName); if (new FileInfo(tmpName).Length == totalLength) { File.Move(tmpName, path, true); } else { throw new Exception("文件下载可能不完整, 请重新下载"); } } }
public static async Task DownloadFile(string url, string path, bool aria2c, string aria2cProxy, bool forceHttp = false) { if (forceHttp) { url = ReplaceUrl(url); } LogDebug("Start downloading: {0}", url); if (!Directory.Exists(Path.GetDirectoryName(Path.GetFullPath(path)))) { Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); } if (aria2c) { await BBDownAria2c.DownloadFileByAria2cAsync(url, path, aria2cProxy); if (File.Exists(path + ".aria2") || !File.Exists(path)) { throw new Exception("aria2下载可能存在错误"); } Console.WriteLine(); return; } int retry = 0; string tmpName = Path.Combine(Path.GetDirectoryName(path), Path.GetFileNameWithoutExtension(path) + ".tmp"); reDown: try { using (var progress = new ProgressBar()) { await RangeDownloadToTmpAsync(0, url, tmpName, 0, null, (_, downloaded, total) => progress.Report((double)downloaded / total)); File.Move(tmpName, path, true); } } catch (Exception) { if (++retry == 3) { throw; } goto reDown; } }
public static async Task MultiThreadDownloadFileAsync(string url, string path, bool aria2c) { if (aria2c) { BBDownAria2c.DownloadFileByAria2c(url, path); if (File.Exists(path + ".aria2") || !File.Exists(path)) { throw new Exception("aria2下载可能存在错误"); } Console.WriteLine(); return; } long fileSize = GetFileSize(url); LogDebug("文件大小:{0} bytes", fileSize); List <Clip> allClips = GetAllClips(url, fileSize); int total = allClips.Count; LogDebug("分段数量:{0}", total); long done = 0; using (var progress = new ProgressBar()) { progress.Report(0); await RunWithMaxDegreeOfConcurrency(8, allClips, async clip => { string tmp = Path.Combine(Path.GetDirectoryName(path), clip.index.ToString("00000") + "_" + Path.GetFileNameWithoutExtension(path) + (Path.GetExtension(path).EndsWith(".mp4") ? ".vclip" : ".aclip")); if (!(File.Exists(tmp) && new FileInfo(tmp).Length == clip.to - clip.from + 1)) { reDown: try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0"); client.DefaultRequestHeaders.Add("Cookie", Program.COOKIE); if (clip.to != -1) { client.DefaultRequestHeaders.Add("Range", $"bytes={clip.from}-{clip.to}"); } else { client.DefaultRequestHeaders.Add("Range", $"bytes={clip.from}-"); } if (!url.Contains("platform=android_tv_yst")) { client.DefaultRequestHeaders.Referrer = new Uri("https://www.bilibili.com"); } var response = await client.GetAsync(url); using (var stream = await response.Content.ReadAsStreamAsync()) { using (var fileStream = new FileStream(tmp, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true)) { var buffer = new byte[8192]; int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead); done += bytesRead; progress.Report((double)done / fileSize); } //await stream.CopyToAsync(fileStream); } } } } catch { goto reDown; } } else { done += new FileInfo(tmp).Length; progress.Report((double)done / fileSize); } }); } }
public static async Task MultiThreadDownloadFileAsync(string url, string path, bool aria2c) { if (aria2c) { BBDownAria2c.DownloadFileByAria2c(url, path); if (File.Exists(path + ".aria2") || !File.Exists(path)) { throw new Exception("aria2下载可能存在错误"); } Console.WriteLine(); return; } long fileSize = GetFileSize(url); LogDebug("文件大小:{0} bytes", fileSize); List <Clip> allClips = GetAllClips(url, fileSize); int total = allClips.Count; LogDebug("分段数量:{0}", total); long done = 0; using (var progress = new ProgressBar()) { progress.Report(0); await RunWithMaxDegreeOfConcurrency(8, allClips, async clip => { string tmp = Path.Combine(Path.GetDirectoryName(path), clip.index.ToString("00000") + "_" + Path.GetFileNameWithoutExtension(path) + (Path.GetExtension(path).EndsWith(".mp4") ? ".vclip" : ".aclip")); if (!(File.Exists(tmp) && new FileInfo(tmp).Length == clip.to - clip.from + 1)) { reDown: try { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0"); client.DefaultRequestHeaders.Add("Cookie", Program.COOKIE); if (clip.to != -1) { client.DefaultRequestHeaders.Add("Range", $"bytes={clip.from}-{clip.to}"); } else { client.DefaultRequestHeaders.Add("Range", $"bytes={clip.from}-"); } if (!url.Contains("platform=android_tv_yst")) { client.DefaultRequestHeaders.Referrer = new Uri("https://www.bilibili.com"); } var response = await client.GetAsync(url); using (var stream = await response.Content.ReadAsStreamAsync()) { using (var fileStream = new FileStream(tmp, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true)) { var buffer = new byte[8192]; int bytesRead; while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await fileStream.WriteAsync(buffer, 0, bytesRead); done += bytesRead; progress.Report((double)done / fileSize); } //await stream.CopyToAsync(fileStream); } } } } catch { goto reDown; } } else { done += new FileInfo(tmp).Length; progress.Report((double)done / fileSize); } }); /*//多线程设置 * ParallelOptions parallelOptions = new ParallelOptions * { * MaxDegreeOfParallelism = 8 * }; * Parallel.ForEach(allClips, parallelOptions, async clip => * { * string tmp = Path.Combine(Path.GetDirectoryName(path), clip.index.ToString("00000") + "_" + Path.GetFileNameWithoutExtension(path) + (Path.GetExtension(path).EndsWith(".mp4") ? ".vclip" : ".aclip")); * if (!(File.Exists(tmp) && new FileInfo(tmp).Length == clip.to - clip.from + 1)) * { * reDown: * try * { *//*HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; * request.Timeout = 30000; * request.ReadWriteTimeout = 30000; //重要 * request.AllowAutoRedirect = true; * request.KeepAlive = false; * request.Method = "GET"; * if (!url.Contains("platform=android_tv_yst")) * request.Referer = "https://www.bilibili.com"; * request.UserAgent = "Mozilla/5.0"; * request.Headers.Add("Cookie", Program.COOKIE); * if (clip.to != -1) * request.AddRange("bytes", clip.from, clip.to); * else * request.AddRange("bytes", clip.from); * using (var response = (HttpWebResponse)request.GetResponse()) * { * using (var responseStream = response.GetResponseStream()) * { * using (var stream = new FileStream(tmp, FileMode.Create, FileAccess.Write, FileShare.Write)) * { * byte[] bArr = new byte[1024]; * int size = responseStream.Read(bArr, 0, (int)bArr.Length); * while (size > 0) * { * stream.Write(bArr, 0, size); * done += size; * progress.Report((double)done / fileSize); * size = responseStream.Read(bArr, 0, (int)bArr.Length); * } * } * } * }*//* * } * catch { goto reDown; } * } * else * { * done += new FileInfo(tmp).Length; * progress.Report((double)done / fileSize); * } * });*/ } }
public static async Task MultiThreadDownloadFileAsync(string url, string path, bool aria2c, string aria2cProxy, bool forceHttp = false) { if (forceHttp) { url = ReplaceUrl(url); } LogDebug("Start downloading: {0}", url); if (aria2c) { await BBDownAria2c.DownloadFileByAria2cAsync(url, path, aria2cProxy); if (File.Exists(path + ".aria2") || !File.Exists(path)) { throw new Exception("aria2下载可能存在错误"); } Console.WriteLine(); return; } long fileSize = await GetFileSizeAsync(url); LogDebug("文件大小:{0} bytes", fileSize); //已下载过, 跳过下载 if (File.Exists(path) && new FileInfo(path).Length == fileSize) { LogDebug("文件已下载过, 跳过下载"); return; } List <Clip> allClips = GetAllClips(url, fileSize); int total = allClips.Count; LogDebug("分段数量:{0}", total); ConcurrentDictionary <int, long> clipProgress = new(); foreach (var i in allClips) { clipProgress[i.index] = 0; } using (var progress = new ProgressBar()) { progress.Report(0); await Parallel.ForEachAsync(allClips, async (clip, _) => { int retry = 0; string tmp = Path.Combine(Path.GetDirectoryName(path), clip.index.ToString("00000") + "_" + Path.GetFileNameWithoutExtension(path) + (Path.GetExtension(path).EndsWith(".mp4") ? ".vclip" : ".aclip")); reDown: try { await RangeDownloadToTmpAsync(clip.index, url, tmp, clip.from, clip.to == -1 ? null : clip.to, (index, downloaded, _) => { clipProgress[index] = downloaded; progress.Report((double)clipProgress.Values.Sum() / fileSize); }, true); } catch (NotSupportedException) { if (++retry == 3) { throw new Exception($"服务器可能并不支持多线程下载,请使用 --multi-thread false 关闭多线程"); } goto reDown; } catch (Exception) { if (++retry == 3) { throw new Exception($"Failed to download clip {clip.index}"); } goto reDown; } }); } }