using AntDesign; using Downloader; using System; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Net; using System.Threading.Tasks; namespace VideoAnalysisCore.Common { /// /// /// public class DownloadFile { static DownloadConfiguration Opt { get; set; } = default!; /// /// 初始化下载器 /// /// 下载速度mb/s 默认8 static void Init(int DownloadSpeed = 8) { Opt = new DownloadConfiguration() { // 通常,主机支持的最大值为8000字节,默认值是8000 BufferBlockSize = 10240, // 要下载的文件部分数量,默认值是1 ChunkCount = 8, // 下载速度限制为2MB/秒,默认值为零(即无限制) MaximumBytesPerSecond = 1024 * 1024 * DownloadSpeed, // 故障转移时的最大重试次数 MaxTryAgainOnFailover = 5, // 每50MB后释放内存缓冲区 MaximumMemoryBufferBytes = 1024 * 1024 * 50, // 是否并行下载文件的各个部分。默认值为false ParallelDownload = true, // 并行下载的数量。默认值与分块数量相同 ParallelCount = 4, // 每个流块读取器的超时时间(毫秒),默认值是1000 Timeout = 1000, // 如果只想下载大型文件的特定字节范围,则设置为true RangeDownload = false, // 大型文件下载范围的起始偏移量 RangeLow = 0, // 大型文件下载范围的结束偏移量 RangeHigh = 0, // 下载失败完成时清除包块数据,默认值为false ClearPackageOnCompletionWithFailure = true, // 将文件分多个部分下载时的最小分块大小,默认值是512 MinimumSizeOfChunking = 1024, // 在开始下载之前,按照文件大小预留文件的存储空间,默认值为false ReserveStorageSpaceBeforeStartingDownload = true, // 在下载进度改变事件中,通过ReceivedBytes获取按需下载的数据 EnableLiveStreaming = false, // 配置和自定义请求头 RequestConfiguration = { Accept = "*/*", //CookieContainer = cookies, Headers = new WebHeaderCollection(), // { 你的自定义头部信息 } KeepAlive = true, // 默认值为false ProtocolVersion = HttpVersion.Version11, // 默认值是HTTP 1.1 UseDefaultCredentials = false, // 你的自定义用户代理或你的应用名称/应用版本。 UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", //Proxy = new WebProxy()//使用代理 //{ // Address = new Uri("http://Learn.VideoAnalysis"), // UseDefaultCredentials = false, // Credentials = System.Net.CredentialCache.DefaultNetworkCredentials, // BypassProxyOnLocal = true //} } }; } // 根据 Content-Type 映射文件后缀 static string GetExtensionFromContentType(HttpResponseMessage res) { var contentType = res.Content.Headers.ContentType?.MediaType; return contentType switch { "application/pdf" => ".pdf", "image/jpeg" => ".jpg", "image/png" => ".png", "application/zip" => ".zip", "text/html" => ".html", "audio/wav" => ".wav", "audio/mp4" => ".mp4", "audio/mp3" => ".mp3", // 根据需要添加其他 Content-Type 映射 _ => ".mp4", // 默认二进制文件 }; } /// /// 使用 HttpClient 下载任务的资源文件到本地 /// /// /// public static async Task RunTask(string task) { if (Opt is null) Init(); //获取资源文件 地址 var fileUrl = RedisExpand.Redis.HMGet(RedisExpandKey.Task(task), "MediaUrl") .FirstOrDefault(); if (string.IsNullOrEmpty(fileUrl)) throw new Exception($"任务id[{task}] 资源地址无效 {fileUrl}"); // 尝试从 URL 中获取文件后缀 string fileExtension = Path.GetExtension(new Uri(fileUrl).AbsolutePath); //否则 获取 从Content-Type 获取文件后缀 if (string.IsNullOrEmpty(fileExtension)) throw new Exception($"未能从资源路径中获取文件后缀"); //创建下载文件缓存路径 if (!Directory.Exists(AppCommon.TaskCachedFile)) Directory.CreateDirectory(AppCommon.TaskCachedFile); var localPath = task.LocalPath(); var outputPath = Path.Combine(localPath, task + fileExtension); if (!Directory.Exists(localPath)) Directory.CreateDirectory(localPath); RedisExpand.Redis.HSet(RedisExpandKey.Task(task), "LocalMediaPath", outputPath); IDownload download = DownloadBuilder.New() .WithUrl(fileUrl) .WithDirectory(localPath) .WithFileName(task + fileExtension) .WithConfiguration(Opt) .Build(); var pI = 0; download.DownloadProgressChanged += (object? sender, Downloader.DownloadProgressChangedEventArgs e) => { pI++; if(pI%20==0) RedisExpand.SetTaskProgress(task, e.ProgressPercentage); }; download.DownloadFileCompleted +=async (object? sender, AsyncCompletedEventArgs e) => { if (download.Status == DownloadStatus.Failed && e.Error!=null) { await RedisExpand.SetTaskErrorMessage(long.Parse(task), e.Error) .ConfigureAwait(false);//不切回上下文 return; } else if (download.Status == DownloadStatus.Completed) { //加入下一队列 RedisExpand.InsertChannel(Enum.RedisChannelEnum.SeparateAudio, task); return; } }; await download.StartAsync(); } } }