增加代理、自定义HLS KEY选项
This commit is contained in:
parent
0b02ecd2c8
commit
e84558d908
|
@ -36,6 +36,9 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
public static string cmd_selectAudio_more { get => GetText("cmd_selectAudio_more"); }
|
||||
public static string cmd_selectSubtitle { get => GetText("cmd_selectSubtitle"); }
|
||||
public static string cmd_selectSubtitle_more { get => GetText("cmd_selectSubtitle_more"); }
|
||||
public static string cmd_customHLSMethod { get => GetText("cmd_customHLSMethod"); }
|
||||
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }
|
||||
public static string cmd_customHLSIv { get => GetText("cmd_customHLSIv"); }
|
||||
public static string cmd_Input { get => GetText("cmd_Input"); }
|
||||
public static string cmd_keys { get => GetText("cmd_keys"); }
|
||||
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
||||
|
@ -57,6 +60,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
public static string cmd_urlProcessorArgs { get => GetText("cmd_urlProcessorArgs"); }
|
||||
public static string cmd_useShakaPackager { get => GetText("cmd_useShakaPackager"); }
|
||||
public static string cmd_concurrentDownload { get => GetText("cmd_concurrentDownload"); }
|
||||
public static string cmd_useSystemProxy { get => GetText("cmd_useSystemProxy"); }
|
||||
public static string cmd_liveKeepSegments { get => GetText("cmd_liveKeepSegments"); }
|
||||
public static string cmd_liveRecordLimit { get => GetText("cmd_liveRecordLimit"); }
|
||||
public static string cmd_liveRealTimeMerge { get => GetText("cmd_liveRealTimeMerge"); }
|
||||
|
|
|
@ -244,17 +244,41 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
zhTW: "錄製直播時即時合併",
|
||||
enUS: "Real-time merge into file when recording live"
|
||||
),
|
||||
["cmd_useSystemProxy"] = new TextContainer
|
||||
(
|
||||
zhCN: "使用系统默认代理",
|
||||
zhTW: "使用系統默認代理",
|
||||
enUS: "Use system default proxy"
|
||||
),
|
||||
["cmd_livePerformAsVod"] = new TextContainer
|
||||
(
|
||||
zhCN: "以点播方式下载直播流",
|
||||
zhTW: "以點播方式下載直播流",
|
||||
enUS: "Download live streams as vod"
|
||||
),
|
||||
["cmd_customHLSMethod"] = new TextContainer
|
||||
(
|
||||
zhCN: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
|
||||
zhTW: "指定HLS加密方式 (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)",
|
||||
enUS: "Set HLS encryption method (AES_128|AES_128_ECB|CENC|CHACHA20|NONE|SAMPLE_AES|SAMPLE_AES_CTR|UNKNOWN)"
|
||||
),
|
||||
["cmd_customHLSKey"] = new TextContainer
|
||||
(
|
||||
zhCN: "指定HLS解密KEY. 可以是文件, HEX或Base64",
|
||||
zhTW: "指定HLS解密KEY. 可以是文件, HEX或Base64",
|
||||
enUS: "Set the HLS decryption key. Can be file, HEX or Base64"
|
||||
),
|
||||
["cmd_customHLSIv"] = new TextContainer
|
||||
(
|
||||
zhCN: "指定HLS解密IV. 可以是文件, HEX或Base64",
|
||||
zhTW: "指定HLS解密IV. 可以是文件, HEX或Base64",
|
||||
enUS: "Set the HLS decryption iv. Can be file, HEX or Base64"
|
||||
),
|
||||
["cmd_liveKeepSegments"] = new TextContainer
|
||||
(
|
||||
zhCN: "录制直播并开启实时合并时依然保留分片",
|
||||
zhTW: "錄製直播並開啟即時合併時依然保留分片",
|
||||
enUS: "Keep segments when recording a live broadcast and enable liveRealTimeMerge"
|
||||
enUS: "Keep segments when recording a live (liveRealTimeMerge enabled)"
|
||||
),
|
||||
["cmd_liveRecordLimit"] = new TextContainer
|
||||
(
|
||||
|
@ -276,9 +300,9 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
),
|
||||
["cmd_selectVideo"] = new TextContainer
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的视频流. 输入 \"--morehelp select-video\" 以查看详细信息.",
|
||||
zhTW: "通過正則表達式選擇符合要求的影片軌. 輸入 \"--morehelp select-video\" 以查看詳細訊息.",
|
||||
enUS: "Select video streams by regular expressions. Use \"--morehelp select-video\" for more details."
|
||||
zhCN: "通过正则表达式选择符合要求的视频流. 输入 \"--morehelp select-video\" 以查看详细信息",
|
||||
zhTW: "通過正則表達式選擇符合要求的影片軌. 輸入 \"--morehelp select-video\" 以查看詳細訊息",
|
||||
enUS: "Select video streams by regular expressions. Use \"--morehelp select-video\" for more details"
|
||||
),
|
||||
["cmd_selectVideo_more"] = new TextContainer
|
||||
(
|
||||
|
@ -312,9 +336,9 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
),
|
||||
["cmd_selectAudio"] = new TextContainer
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的音频流. 输入 \"--morehelp select-audio\" 以查看详细信息.",
|
||||
zhTW: "通過正則表達式選擇符合要求的音軌. 輸入 \"--morehelp select-audio\" 以查看詳細訊息.",
|
||||
enUS: "Select audio streams by regular expressions. Use \"--morehelp select-audio\" for more details."
|
||||
zhCN: "通过正则表达式选择符合要求的音频流. 输入 \"--morehelp select-audio\" 以查看详细信息",
|
||||
zhTW: "通過正則表達式選擇符合要求的音軌. 輸入 \"--morehelp select-audio\" 以查看詳細訊息",
|
||||
enUS: "Select audio streams by regular expressions. Use \"--morehelp select-audio\" for more details"
|
||||
),
|
||||
["cmd_selectAudio_more"] = new TextContainer
|
||||
(
|
||||
|
@ -345,9 +369,9 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
),
|
||||
["cmd_selectSubtitle"] = new TextContainer
|
||||
(
|
||||
zhCN: "通过正则表达式选择符合要求的字幕流. 输入 \"--morehelp select-subtitle\" 以查看详细信息.",
|
||||
zhTW: "通過正則表達式選擇符合要求的字幕流. 輸入 \"--morehelp select-subtitle\" 以查看詳細訊息.",
|
||||
enUS: "Select subtitle streams by regular expressions. Use \"--morehelp select-subtitle\" for more details."
|
||||
zhCN: "通过正则表达式选择符合要求的字幕流. 输入 \"--morehelp select-subtitle\" 以查看详细信息",
|
||||
zhTW: "通過正則表達式選擇符合要求的字幕流. 輸入 \"--morehelp select-subtitle\" 以查看詳細訊息",
|
||||
enUS: "Select subtitle streams by regular expressions. Use \"--morehelp select-subtitle\" for more details"
|
||||
),
|
||||
["cmd_selectSubtitle_more"] = new TextContainer
|
||||
(
|
||||
|
@ -411,15 +435,15 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
),
|
||||
["cmd_muxAfterDone"] = new TextContainer
|
||||
(
|
||||
zhCN: "所有工作完成时尝试混流分离的音视频. 输入 \"--morehelp mux-after-done\" 以查看详细信息.",
|
||||
zhTW: "所有工作完成時嘗試混流分離的影音. 輸入 \"--morehelp mux-after-done\" 以查看詳細訊息.",
|
||||
enUS: "When all works is done, try to mux the downloaded streams. Use \"--morehelp mux-after-done\" for more details."
|
||||
zhCN: "所有工作完成时尝试混流分离的音视频. 输入 \"--morehelp mux-after-done\" 以查看详细信息",
|
||||
zhTW: "所有工作完成時嘗試混流分離的影音. 輸入 \"--morehelp mux-after-done\" 以查看詳細訊息",
|
||||
enUS: "When all works is done, try to mux the downloaded streams. Use \"--morehelp mux-after-done\" for more details"
|
||||
),
|
||||
["cmd_muxImport"] = new TextContainer
|
||||
(
|
||||
zhCN: "混流时引入外部媒体文件. 输入 \"--morehelp mux-import\" 以查看详细信息.",
|
||||
zhTW: "混流時引入外部媒體檔案. 輸入 \"--morehelp mux-import\" 以查看詳細訊息.",
|
||||
enUS: "When MuxAfterDone enabled, allow to import local media files. Use \"--morehelp mux-import\" for more details."
|
||||
zhCN: "混流时引入外部媒体文件. 输入 \"--morehelp mux-import\" 以查看详细信息",
|
||||
zhTW: "混流時引入外部媒體檔案. 輸入 \"--morehelp mux-import\" 以查看詳細訊息",
|
||||
enUS: "When MuxAfterDone enabled, allow to import local media files. Use \"--morehelp mux-import\" for more details"
|
||||
),
|
||||
["cmd_muxImport_more"] = new TextContainer
|
||||
(
|
||||
|
|
|
@ -23,13 +23,14 @@ namespace N_m3u8DL_RE.Common.Util
|
|||
{
|
||||
public class HTTPUtil
|
||||
{
|
||||
|
||||
public static readonly HttpClient AppHttpClient = new(new HttpClientHandler
|
||||
public static readonly HttpClientHandler HttpClientHandler = new()
|
||||
{
|
||||
AllowAutoRedirect = false,
|
||||
AutomaticDecompression = DecompressionMethods.All,
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
||||
})
|
||||
};
|
||||
|
||||
public static readonly HttpClient AppHttpClient = new(HttpClientHandler)
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
|
|
|
@ -13,6 +13,25 @@ namespace N_m3u8DL_RE.Common.Util
|
|||
return BitConverter.ToString(data).Replace("-", split);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是不是HEX字符串
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryParseHexString(string input, out byte[]? bytes)
|
||||
{
|
||||
bytes = null;
|
||||
input = input.ToUpper();
|
||||
if (input.StartsWith("0X"))
|
||||
input = input[2..];
|
||||
if (input.Length % 2 != 0)
|
||||
return false;
|
||||
if (input.Any(c => !"0123456789ABCDEF".Contains(c)))
|
||||
return false;
|
||||
bytes = HexToBytes(input);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static byte[] HexToBytes(string hex)
|
||||
{
|
||||
hex = hex.Trim();
|
||||
|
|
|
@ -318,18 +318,6 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
|||
//解析KEY
|
||||
else if (line.StartsWith(HLSTags.ext_x_key))
|
||||
{
|
||||
//自定义KEY情况 不读取当前行的KEY信息.
|
||||
//对于IV,没自定义且当前行有IV的话 就用
|
||||
if (ParserConfig.CustomeKey != null)
|
||||
{
|
||||
currentEncryptInfo.Key = ParserConfig.CustomeKey;
|
||||
if (ParserConfig.CustomeIV == null && line.Contains("IV=0x"))
|
||||
currentEncryptInfo.IV = HexUtil.HexToBytes(ParserUtil.GetAttribute(line, "IV"));
|
||||
continue;
|
||||
}
|
||||
|
||||
var iv = ParserUtil.GetAttribute(line, "IV");
|
||||
var method = ParserUtil.GetAttribute(line, "METHOD");
|
||||
var uri = ParserUtil.GetAttribute(line, "URI");
|
||||
var uri_last = ParserUtil.GetAttribute(lastKeyLine, "URI");
|
||||
|
||||
|
|
|
@ -28,12 +28,21 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
|||
Logger.Debug("METHOD:{},URI:{},IV:{}", method, uri, iv);
|
||||
|
||||
var encryptInfo = new EncryptInfo(method);
|
||||
|
||||
//处理自定义加密方式
|
||||
if (parserConfig.CustomMethod != null)
|
||||
{
|
||||
encryptInfo.Method = parserConfig.CustomMethod.Value;
|
||||
Logger.Warn("METHOD changed to {}", method, encryptInfo.Method);
|
||||
}
|
||||
|
||||
//IV
|
||||
if (!string.IsNullOrEmpty(iv))
|
||||
{
|
||||
encryptInfo.IV = HexUtil.HexToBytes(iv);
|
||||
}
|
||||
if (parserConfig.CustomeIV != null)
|
||||
//自定义IV
|
||||
if (parserConfig.CustomeIV != null && parserConfig.CustomeIV.Length > 0)
|
||||
{
|
||||
encryptInfo.IV = parserConfig.CustomeIV;
|
||||
}
|
||||
|
@ -41,7 +50,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
|||
//KEY
|
||||
try
|
||||
{
|
||||
if (parserConfig.CustomeKey != null)
|
||||
if (parserConfig.CustomeKey != null && parserConfig.CustomeKey.Length > 0)
|
||||
{
|
||||
encryptInfo.Key = parserConfig.CustomeKey;
|
||||
}
|
||||
|
@ -75,7 +84,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
|||
{
|
||||
Logger.WarnMarkUp($"[grey]{_ex.Message.EscapeMarkup()} retryCount: {retryCount}[/]");
|
||||
Thread.Sleep(1000);
|
||||
if (retryCount > 0) goto getHttpKey;
|
||||
if (retryCount-- > 0) goto getHttpKey;
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using N_m3u8DL_RE.Common.Log;
|
||||
using N_m3u8DL_RE.Common.Enum;
|
||||
using N_m3u8DL_RE.Common.Log;
|
||||
using N_m3u8DL_RE.Common.Resource;
|
||||
using N_m3u8DL_RE.Common.Util;
|
||||
using N_m3u8DL_RE.Entity;
|
||||
using N_m3u8DL_RE.Enum;
|
||||
using N_m3u8DL_RE.Util;
|
||||
|
@ -48,9 +50,18 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
||||
private readonly static Option<bool> ConcurrentDownload = new(new string[] { "-mt", "--concurrent-download" }, description: ResString.cmd_concurrentDownload, getDefaultValue: () => false);
|
||||
|
||||
//代理选项
|
||||
private readonly static Option<bool> UseSystemProxy = new(new string[] { "--use-system-proxy" }, description: ResString.cmd_useSystemProxy, getDefaultValue: () => true);
|
||||
|
||||
//morehelp
|
||||
private readonly static Option<string?> MoreHelp = new(new string[] { "--morehelp" }, description: ResString.cmd_moreHelp) { ArgumentHelpName = "OPTION" };
|
||||
|
||||
//自定义KEY等
|
||||
private readonly static Option<EncryptMethod?> CustomHLSMethod = new(name: "--custom-hls-method", description: ResString.cmd_customHLSMethod) { ArgumentHelpName = "METHOD" };
|
||||
private readonly static Option<byte[]?> CustomHLSKey = new(name: "--custom-hls-key", description: ResString.cmd_customHLSKey, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
||||
private readonly static Option<byte[]?> CustomHLSIv = new(name: "--custom-hls-iv", description: ResString.cmd_customHLSIv, parseArgument: ParseHLSCustomKey) { ArgumentHelpName = "FILE|HEX|BASE64" };
|
||||
|
||||
|
||||
//直播相关
|
||||
private readonly static Option<bool> LivePerformAsVod = new(new string[] { "--live-perform-as-vod" }, description: ResString.cmd_livePerformAsVod, getDefaultValue: () => false);
|
||||
private readonly static Option<bool> LiveRealTimeMerge = new(new string[] { "--live-real-time-merge" }, description: ResString.cmd_liveRealTimeMerge, getDefaultValue: () => false);
|
||||
|
@ -65,6 +76,32 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
private readonly static Option<StreamFilter?> AudioFilter = new(new string[] { "-sa", "--select-audio" }, description: ResString.cmd_selectAudio, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||
private readonly static Option<StreamFilter?> SubtitleFilter = new(new string[] { "-ss", "--select-subtitle" }, description: ResString.cmd_selectSubtitle, parseArgument: ParseStreamFilter) { ArgumentHelpName = "OPTIONS" };
|
||||
|
||||
/// <summary>
|
||||
/// 解析自定义KEY
|
||||
/// </summary>
|
||||
/// <param name="result"></param>
|
||||
/// <returns></returns>
|
||||
private static byte[]? ParseHLSCustomKey(ArgumentResult result)
|
||||
{
|
||||
var input = result.Tokens.First().Value;
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
return null;
|
||||
if (File.Exists(input))
|
||||
return File.ReadAllBytes(input);
|
||||
else if (HexUtil.TryParseHexString(input, out byte[]? bytes))
|
||||
return bytes;
|
||||
else
|
||||
return Convert.FromBase64String(input);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
result.ErrorMessage = "error in parse hls custom key: " + input;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析录制直播时长限制
|
||||
/// </summary>
|
||||
|
@ -302,6 +339,10 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
LiveKeepSegments = bindingContext.ParseResult.GetValueForOption(LiveKeepSegments),
|
||||
LiveRecordLimit = bindingContext.ParseResult.GetValueForOption(LiveRecordLimit),
|
||||
LivePerformAsVod = bindingContext.ParseResult.GetValueForOption(LivePerformAsVod),
|
||||
UseSystemProxy = bindingContext.ParseResult.GetValueForOption(UseSystemProxy),
|
||||
CustomHLSMethod = bindingContext.ParseResult.GetValueForOption(CustomHLSMethod),
|
||||
CustomHLSKey = bindingContext.ParseResult.GetValueForOption(CustomHLSKey),
|
||||
CustomHLSIv = bindingContext.ParseResult.GetValueForOption(CustomHLSIv),
|
||||
};
|
||||
|
||||
var parsedHeaders = bindingContext.ParseResult.GetValueForOption(Headers);
|
||||
|
@ -362,6 +403,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
FFmpegBinaryPath,
|
||||
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
||||
MuxAfterDone,
|
||||
CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy,
|
||||
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LiveRecordLimit,
|
||||
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, MoreHelp
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using N_m3u8DL_RE.Common.Log;
|
||||
using N_m3u8DL_RE.Common.Enum;
|
||||
using N_m3u8DL_RE.Common.Log;
|
||||
using N_m3u8DL_RE.Entity;
|
||||
using N_m3u8DL_RE.Enum;
|
||||
|
||||
|
@ -123,6 +124,10 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
/// </summary>
|
||||
public bool LivePerformAsVod { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.UseSystemProxy"/>.
|
||||
/// </summary>
|
||||
public bool UseSystemProxy { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.SubtitleFormat"/>.
|
||||
/// </summary>
|
||||
public SubtitleFormat SubtitleFormat { get; set; }
|
||||
|
@ -174,6 +179,18 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
/// See: <see cref="CommandInvoker.SubtitleFilter"/>.
|
||||
/// </summary>
|
||||
public StreamFilter? SubtitleFilter { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.CustomHLSMethod"/>.
|
||||
/// </summary>
|
||||
public EncryptMethod? CustomHLSMethod { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.CustomHLSKey"/>.
|
||||
/// </summary>
|
||||
public byte[]? CustomHLSKey { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.CustomHLSIv"/>.
|
||||
/// </summary>
|
||||
public byte[]? CustomHLSIv { get; set; }
|
||||
public bool MuxKeepFiles { get; set; }
|
||||
}
|
||||
}
|
|
@ -58,6 +58,11 @@ namespace N_m3u8DL_RE
|
|||
{
|
||||
Logger.LogLevel = option.LogLevel;
|
||||
|
||||
if (option.UseSystemProxy == false)
|
||||
{
|
||||
HTTPUtil.HttpClientHandler.UseProxy = false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//检查互斥的选项
|
||||
|
@ -130,7 +135,10 @@ namespace N_m3u8DL_RE
|
|||
AppendUrlParams = option.AppendUrlParams,
|
||||
UrlProcessorArgs = option.UrlProcessorArgs,
|
||||
BaseUrl = option.BaseUrl!,
|
||||
Headers = headers
|
||||
Headers = headers,
|
||||
CustomMethod = option.CustomHLSMethod,
|
||||
CustomeKey = option.CustomHLSKey,
|
||||
CustomeIV = option.CustomHLSIv,
|
||||
};
|
||||
|
||||
//demo1
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using N_m3u8DL_RE.Common.Log;
|
||||
using N_m3u8DL_RE.Common.Resource;
|
||||
using N_m3u8DL_RE.Common.Util;
|
||||
using N_m3u8DL_RE.Entity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -14,15 +15,7 @@ namespace N_m3u8DL_RE.Util
|
|||
{
|
||||
internal class DownloadUtil
|
||||
{
|
||||
private static readonly HttpClient AppHttpClient = new(new HttpClientHandler
|
||||
{
|
||||
AllowAutoRedirect = false,
|
||||
AutomaticDecompression = DecompressionMethods.All,
|
||||
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true
|
||||
})
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
private static readonly HttpClient AppHttpClient = HTTPUtil.AppHttpClient;
|
||||
|
||||
public static async Task<DownloadResult> DownloadToFileAsync(string url, string path, SpeedContainer speedContainer, Dictionary<string, string>? headers = null, long? fromPosition = null, long? toPosition = null)
|
||||
{
|
||||
|
|
|
@ -8,9 +8,9 @@ namespace N_m3u8DL_RE.Util
|
|||
{
|
||||
internal class OtherUtil
|
||||
{
|
||||
public static Dictionary<string,string> SplitHeaderArrayToDic(string[]? headers)
|
||||
public static Dictionary<string, string> SplitHeaderArrayToDic(string[]? headers)
|
||||
{
|
||||
Dictionary<string,string> dic = new();
|
||||
Dictionary<string, string> dic = new();
|
||||
|
||||
if (headers != null)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue