public static void run__v2(string M3U8_FILE_URL, string OUTPUT_FILE_DIR, string OUTPUT_FILE_EXT) { using (var mc = m3u8_client_factory.Create()) using (var cts = new CancellationTokenSource()) { var task = Task.Run(async() => { var sw = Stopwatch.StartNew(); //-1-// CONSOLE.WriteLine($"download m3u8-file: '{M3U8_FILE_URL}'..."); var m3u8FileUrl = new Uri(M3U8_FILE_URL); var m3u8File = await mc.DownloadFile(m3u8FileUrl, cts.Token); CONSOLE.WriteLine($"success. parts count: {m3u8File.Parts.Count}\r\n"); //-2-// var downloadParts = download_m3u8File_parallel__v2(mc, m3u8File, cts); //-3-// var downloadPartsSuccessCount = 0; var downloadPartsErrorCount = 0; var totalBytes = 0; var outputFileName = Path.Combine(OUTPUT_FILE_DIR, PathnameCleaner.CleanPathnameAndFilename(m3u8FileUrl.AbsolutePath).TrimStart('-') + OUTPUT_FILE_EXT); using (var fs = File.OpenWrite(outputFileName)) { fs.SetLength(0); foreach (var downloadPart in downloadParts) { if (downloadPart.Error != null) { downloadPartsErrorCount++; continue; } var bytes = downloadPart.Bytes; fs.Write(bytes, 0, bytes.Length); downloadPartsSuccessCount++; totalBytes += bytes.Length; } } sw.Stop(); CONSOLE.WriteLine($"\r\nSuccess: downloaded & writed parts {downloadPartsSuccessCount} of {(downloadPartsErrorCount + downloadPartsSuccessCount)}\r\n" + $"(elapsed: {sw.Elapsed}, file: '{outputFileName}', size: {(totalBytes >> 20).ToString( "0,0" )} mb)\r\n"); }) .ContinueWith(t => { if (t.IsFaulted) { CONSOLE.WriteLineError("ERROR: " + t.Exception); } }); #region [.wait for keyboard break.] task.WaitForTaskEndsOrKeyboardBreak(cts); #endregion } }
private static IReadOnlyCollection <m3u8_part_ts> download_m3u8File_parallel(m3u8_client mc, m3u8_file_t m3u8_file , CancellationTokenSource cts = null, int maxDegreeOfParallelism = 64) { var ct = (cts?.Token).GetValueOrDefault(CancellationToken.None); var baseAddress = m3u8_file.BaseAddress; var totalPatrs = m3u8_file.Parts.Count; var globalPartNumber = 0; var downloadPartsSet = new SortedSet <m3u8_part_ts>(default(m3u8_part_ts.comparer)); using (DefaultConnectionLimitSaver.Create(maxDegreeOfParallelism)) { Parallel.ForEach(m3u8_file.Parts, new ParallelOptions() { MaxDegreeOfParallelism = maxDegreeOfParallelism, CancellationToken = ct }, (part, loopState, idx) => { var n = Interlocked.Increment(ref globalPartNumber); try { CONSOLE.WriteLine($"#{n} of {totalPatrs}). '{part.RelativeUrlName}'..."); var downloadPart = mc.DownloadPart(part, baseAddress, ct).Result; if ((downloadPart.Error != null) && !ct.IsCancellationRequested) { CONSOLE.WriteLineError($"#{n} of {totalPatrs}). FAILED: {downloadPart.Error}{Environment.NewLine}"); } lock ( downloadPartsSet ) { downloadPartsSet.Add(downloadPart); } } catch (Exception ex) { #region [.code.] var aex = ex as AggregateException; if ((aex == null) || !aex.InnerExceptions.All(e => (e is OperationCanceledException))) { CONSOLE.WriteLineError("ERROR: " + ex); } #endregion } }); } ct.ThrowIfCancellationRequested(); CONSOLE.WriteLine($"\r\n total parts processed: {globalPartNumber} of {totalPatrs}"); return(downloadPartsSet); }
private static void Main(string[] args) { try { #region [.set SecurityProtocol to 'Tls + Tls11 + Tls12 + Ssl3'.] ServicePointManager.SecurityProtocol = (SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3); #endregion var M3U8_FILE_URL = ConfigurationManager.AppSettings["M3U8_FILE_URL"]; if (M3U8_FILE_URL.IsNullOrWhiteSpace()) { throw (new ArgumentNullException(nameof(M3U8_FILE_URL))); } var OUTPUT_FILE_DIR = ConfigurationManager.AppSettings["OUTPUT_FILE_DIR"]; if (OUTPUT_FILE_DIR.IsNullOrWhiteSpace()) { OUTPUT_FILE_DIR = @"E:\\"; } var OUTPUT_FILE_EXT = ConfigurationManager.AppSettings["OUTPUT_FILE_EXT"]; if (OUTPUT_FILE_EXT.IsNullOrWhiteSpace()) { OUTPUT_FILE_EXT = ".avi"; } //---v1.run( M3U8_FILE_URL, OUTPUT_FILE_DIR, OUTPUT_FILE_EXT ); //v2.run__v1( M3U8_FILE_URL, OUTPUT_FILE_DIR, OUTPUT_FILE_EXT ); //v2.run__v2( M3U8_FILE_URL, OUTPUT_FILE_DIR, OUTPUT_FILE_EXT ); using (var cts = new CancellationTokenSource()) { var outputFileName = Path.Combine(OUTPUT_FILE_DIR, PathnameCleaner.CleanPathnameAndFilename(M3U8_FILE_URL).TrimStart('-') + OUTPUT_FILE_EXT); v3.run(M3U8_FILE_URL, outputFileName, cts).WaitForTaskEndsOrKeyboardBreak(cts); } } catch (Exception ex) { CONSOLE.WriteLineError("ERROR: " + ex); } CONSOLE.WriteLine("\r\n\r\n[.....finita fusking comedy.....]\r\n\r\n", ConsoleColor.DarkGray); CONSOLE.ReadLine(); }
public static async Task run(string m3u8FileUrl, string outputFileName, CancellationTokenSource cts) { var p = new m3u8_processor.DownloadFileAndSaveInputParams() { Cts = cts, m3u8FileUrl = m3u8FileUrl, OutputFileName = outputFileName, ResponseStepAction = new m3u8_processor.ResponseStepActionDelegate(t => CONSOLE.WriteLine($"{t.Part.OrderNumber} of {t.TotalPartCount}, '{t.Part.RelativeUrlName}'") ), }; await m3u8_processor.DownloadFileAndSave_Async(p); }
private static IEnumerable <m3u8_part_ts> download_m3u8File_parallel__v2(m3u8_client mc, m3u8_file_t m3u8_file , CancellationTokenSource cts = null, int maxDegreeOfParallelism = 64) { var ct = (cts?.Token).GetValueOrDefault(CancellationToken.None); var baseAddress = m3u8_file.BaseAddress; var totalPatrs = m3u8_file.Parts.Count; var successPartNumber = 0; var expectedPartNumber = m3u8_file.Parts.FirstOrDefault().OrderNumber; var maxPartNumber = m3u8_file.Parts.LastOrDefault().OrderNumber; var sourceQueue = new Queue <m3u8_part_ts>(m3u8_file.Parts); var downloadPartsSet = new SortedSet <m3u8_part_ts>(default(m3u8_part_ts.comparer)); using (DefaultConnectionLimitSaver.Create(maxDegreeOfParallelism)) using (var canExtractPartEvent = new AutoResetEvent(false)) using (var semaphore = new SemaphoreSlim(maxDegreeOfParallelism)) { var task_download = Task.Run(() => { for ( ; sourceQueue.Count != 0;) { semaphore.Wait(); var part = sourceQueue.Dequeue(); #if DEBUG CONSOLE.WriteLine($"start download part: {part}..."); #endif mc.DownloadPart(part, baseAddress, ct) .ContinueWith(t => { if (t.IsFaulted) { Interlocked.Increment(ref expectedPartNumber); CONSOLE.WriteLine($"'{t.Exception.GetType().Name}': '{t.Exception.Message}'.", ConsoleColor.Red); } else if (!t.IsCanceled) { Interlocked.Increment(ref successPartNumber); var downloadPart = t.Result; #if DEBUG CONSOLE.WriteLine($"end download part: {downloadPart}."); #endif lock ( downloadPartsSet ) { downloadPartsSet.Add(downloadPart); canExtractPartEvent.Set(); } } }); } }, ct); for ( ; expectedPartNumber <= maxPartNumber && !ct.IsCancellationRequested;) { #if DEBUG CONSOLE.WriteLine($"wait part #{expectedPartNumber}..."); #endif canExtractPartEvent.WaitOne(); lock ( downloadPartsSet ) { for ( ; downloadPartsSet.Count != 0;) { var min_part = downloadPartsSet.Min; if (expectedPartNumber == min_part.OrderNumber) { CONSOLE.WriteLine($"receive part #{expectedPartNumber}."); downloadPartsSet.Remove(min_part); Interlocked.Increment(ref expectedPartNumber); semaphore.Release(); yield return(min_part); } else { break; } } } } } ct.ThrowIfCancellationRequested(); CONSOLE.WriteLine($"\r\n total parts processed: {successPartNumber} of {totalPatrs}"); }
private static void Main(string[] args) { try { var M3U8_FILE_URL = ConfigurationManager.AppSettings["M3U8_FILE_URL"]; if (M3U8_FILE_URL.IsNullOrWhiteSpace()) { throw (new ArgumentNullException(nameof(M3U8_FILE_URL))); } var OUTPUT_FILE_DIR = ConfigurationManager.AppSettings["OUTPUT_FILE_DIR"]; if (OUTPUT_FILE_DIR.IsNullOrWhiteSpace()) { OUTPUT_FILE_DIR = Environment.CurrentDirectory; } var OUTPUT_FILE_EXT = ConfigurationManager.AppSettings["OUTPUT_FILE_EXT"]; if (OUTPUT_FILE_EXT.IsNullOrWhiteSpace()) { OUTPUT_FILE_EXT = ".avi"; } //----------------------------------------------------------------------------------// CONSOLE.WriteLine($"M3U8-FILE-URL: '{M3U8_FILE_URL}'..."); CONSOLE.WriteLine("(press 'escape' for cancel)\r\n", ConsoleColor.DarkGray); using (var cts = new CancellationTokenSource()) { var outputFileName = Path.Combine(OUTPUT_FILE_DIR, PathnameCleaner.CleanPathnameAndFilename(M3U8_FILE_URL).TrimStart('-') + OUTPUT_FILE_EXT); var ip = new m3u8_processor.DownloadFileAndSaveInputParams() { Cts = cts, m3u8FileUrl = M3U8_FILE_URL, OutputFileName = outputFileName, MaxDegreeOfParallelism = 64, NetParams = new m3u8_client.init_params() { AttemptRequestCount = 3, Timeout = TimeSpan.FromSeconds(30), ConnectionClose = false, }, RequestStepAction = new m3u8_processor.RequestStepActionDelegate(p => { var msg = $"{p.PartOrderNumber} of {p.TotalPartCount}, '{p.Part.RelativeUrlName}'"; if (p.Error != null) { CONSOLE.WriteLineError(msg + $" => {p.Error}"); } else { CONSOLE.WriteLine(msg); } }), ResponseStepAction = new m3u8_processor.ResponseStepActionDelegate(p => { if (p.Part.Error != null) { CONSOLE.WriteLineError($" => {p.Part.Error}"); } }), }; var res = m3u8_processor.DownloadFileAndSave_Async(ip).WaitForTaskEndsOrKeyboardBreak(cts); CONSOLE.WriteLine($"\r\nM3U8-FILE-URL: '{res.m3u8FileUrl}'"); CONSOLE.WriteLine($"OutputFileName: '{res.OutputFileName}'"); CONSOLE.WriteLine($"OutputFileName-Size: {(res.TotalBytes >> 20)}mb"); CONSOLE.WriteLine($"Total-Parts: {res.TotalParts}, Success: {res.PartsSuccessCount}, Error: {res.PartsErrorCount}"); } } catch (Exception ex) { CONSOLE.WriteLineError("ERROR: " + ex); } CONSOLE.WriteLine("\r\n\r\n[.....finita fusking comedy.....]\r\n\r\n", ConsoleColor.DarkGray); CONSOLE.ReadLine(); }