public download_m3u8File_parts_parallel_params_t(m3u8_client _mc, m3u8_file_t _m3u8File, DownloadFileAndSaveInputParams ip) : this() { mc = _mc; m3u8File = _m3u8File; cts = ip.Cts; requestStepAction = ip.RequestStepAction; responseStepAction = ip.ResponseStepAction; maxDegreeOfParallelism = ip.MaxDegreeOfParallelism; }
public static m3u8_file_t Parse(string content, Uri baseAddress) { var lines = from row in content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) let line = row.Trim() where (!line.IsNullOrEmpty() && !line.StartsWith("#")) select line ; var parts = lines.Select((line, i) => new m3u8_part_ts(line, i)); var o = new m3u8_file_t() { Parts = parts.ToList().AsReadOnly(), BaseAddress = baseAddress, RawText = content, }; return(o); }
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 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); }