1
mirror of https://github.com/nilaoda/N_m3u8DL-CLI synced 2025-09-10 12:40:52 +02:00

Compare commits

...

114 Commits
2.8.2 ... 2.9.9

Author SHA1 Message Date
nilaoda
6c3340e94e 2.9.9 2021-11-23 15:22:09 +08:00
nilaoda
051faa9f2b 修复重试失效问题 2021-11-23 14:37:50 +08:00
nilaoda
115f9c9424 update image 2021-11-20 10:52:01 +08:00
nilaoda
faf67cd527 2.9.8 2021-11-20 10:14:31 +08:00
nilaoda
38d1a1a2dc 修正init url缺失baseurl问题 2021-11-12 23:28:35 +08:00
nilaoda
12eb68d592 修复日志冲突问题 2021-10-19 11:14:41 +08:00
nilaoda
0804e295e5 修复流选择的显示bug 2021-10-19 10:53:03 +08:00
nilaoda
847c4683cb update wetv js 2021-10-17 00:51:46 +08:00
nilaoda
8c72947860 package exe only 2021-10-17 00:24:34 +08:00
nilaoda
f0b240a6ee 优化AppleTV处理 2021-09-05 19:21:08 +08:00
nilaoda
793cf53042 解决同一个period且同id导致被重复添加分片 2021-09-05 18:17:05 +08:00
nilaoda
612fc29197 修复padding负值问题 2021-09-02 22:41:16 +08:00
nilaoda
307e2389de Update README.md 2021-09-02 10:46:11 +08:00
nilaoda
1c932abdc3 Update AssemblyInfo.cs 2021-08-23 11:38:19 +08:00
nilaoda
314f0065c7 fix node select bug and type show bug #496 2021-08-23 11:35:14 +08:00
nilaoda
59060bb74d Merge pull request #495 from ncnnnnn/patch-2
Update README.md
2021-08-21 22:30:13 +08:00
ncnnnnn
cab882c3a3 Update README.md 2021-08-21 20:35:02 +08:00
nilaoda
9955532ce5 强校验MAP下载成功 2021-08-15 20:18:06 +08:00
nilaoda
7e127be8c2 初步修改显示输出样式 2021-08-15 15:32:01 +08:00
nilaoda
b46571a57f Merge pull request #470 from CW-B-W/master
Fix typos in README_ENG.md
2021-07-18 02:28:52 +08:00
Chiao-Wei Wang
da5861d907 Update README_ENG.md 2021-07-18 01:57:16 +08:00
nilaoda
92bc91a1fb drm-json to m3u8 2021-07-04 00:40:05 +08:00
nilaoda
439f50103e 1.支持iq-drm格式json自动转换 2.优化master选择最高清晰度逻辑 2021-07-04 00:38:17 +08:00
nilaoda
8a95e31b2f update docs 2021-07-03 22:35:00 +08:00
nilaoda
115b8a156a Update packages.config 2021-06-27 23:06:33 +08:00
nilaoda
120bcaebb5 Update N_m3u8DL-CLI.csproj 2021-06-27 23:01:22 +08:00
nilaoda
455d56707c Update N_m3u8DL-CLI.csproj 2021-06-27 22:55:05 +08:00
nilaoda
048adcf118 支持解压brotli 2021-06-27 22:41:12 +08:00
nilaoda
fe5aa27b1c 修正判断png图片时可能出现的数组越界bug 2021-06-27 22:39:16 +08:00
nilaoda
039aa489b1 优化范围选择结尾识别 2021-06-27 22:38:32 +08:00
nilaoda
14e80f0b06 优化输出并增加ETA显示 2021-03-27 14:04:31 +08:00
nilaoda
2256fff549 日志文件初始化时,精确到毫秒防止重复 2021-03-27 14:03:54 +08:00
nilaoda
84cfd4e138 Update README_ENG.md 2021-03-26 09:35:28 +08:00
nilaoda
e70c229135 Update README.md 2021-03-26 09:30:30 +08:00
nilaoda
8b520d0c19 修正AppleTV逻辑 2021-03-25 23:11:18 +08:00
nilaoda
71d69de51a Update changelog.txt 2021-03-25 22:09:44 +08:00
nilaoda
bc89ead00d 为下载分片增加了自动重试机制(3次) 2021-03-25 22:09:26 +08:00
nilaoda
ae79d6eb3a 优化下载监控 2021-03-25 22:07:04 +08:00
nilaoda
96bd8af883 适配AppleTv资源 2021-03-22 23:18:22 +08:00
nilaoda
89b1e30e0f 修复enableAudioOnly且下载MPD文件时留下冗余(Audio)文件夹的情况 2021-03-22 23:17:09 +08:00
nilaoda
7a741359ab Update README.md 2021-03-04 13:17:07 +08:00
nilaoda
564b6ad291 Update README_ENG.md 2021-03-04 13:12:06 +08:00
nilaoda
a0fc9404f7 Update README.md 2021-03-04 13:11:06 +08:00
nilaoda
5267be1699 Update changelog.txt 2021-03-04 12:26:20 +08:00
nilaoda
20bfda39e7 bug fix
- 修复M3U8选择音轨/字幕不生效问题
  - 外挂音轨时enableAudioOnly可仅下载音频
2021-03-04 12:23:51 +08:00
nilaoda
ba4c0eeda7 Update Program.cs 2021-02-22 11:58:52 +08:00
nilaoda
5d72e24002 update docs 2021-02-22 11:16:45 +08:00
nilaoda
a87c051d23 update readme 2021-02-22 11:00:32 +08:00
nilaoda
44e1b68d6b update help info 2021-02-22 10:57:53 +08:00
nilaoda
e65dfa52cd Merge pull request #375 from evanlabs/master
添加用户网络代理支持,使用--proxyAddress指定代理地址。
2021-02-22 10:49:42 +08:00
EvanYeung
965c173899 添加用户网络代理支持,使用--proxyAddress指定代理地址。 2021-02-22 09:50:18 +08:00
nilaoda
880af02cc2 打印MPD解析日志 2021-02-21 15:13:44 +08:00
nilaoda
2742de43c4 增加键值 2021-02-21 15:13:07 +08:00
nilaoda
9d8cb57390 MPD检测最后一个分片是否有效 2021-02-21 13:24:15 +08:00
nilaoda
9e2a192dab Update changelog.txt 2021-02-21 13:23:57 +08:00
nilaoda
33cf9e2256 Update Parser.cs 2021-02-11 17:06:19 +08:00
nilaoda
2959cbbb5c Update changelog.txt 2021-02-11 17:06:08 +08:00
nilaoda
c2eb8a6adc 修正MPD拼接BaseUrl逻辑 2021-02-10 22:32:06 +08:00
nilaoda
e1b591b81c Update N_m3u8DL-CLI.csproj 2021-02-03 11:54:02 +08:00
nilaoda
334b1939b5 修复气球云;优化独播库 2021-02-03 00:38:57 +08:00
nilaoda
7e916b65fd Update changelog.txt 2021-02-01 22:57:37 +08:00
nilaoda
4ead563fa2 修正自定义KEY切存在IV时的隐患 2021-02-01 22:57:27 +08:00
nilaoda
1b387a06e5 update docs 2021-02-01 22:52:07 +08:00
nilaoda
6e7b4ac7ea ddyun识别90mm 2021-02-01 22:42:56 +08:00
nilaoda
e98c5205d1 优化跳过png的算法 2021-02-01 14:18:03 +08:00
nilaoda
d7890dd124 优化跳过png的算法 2021-02-01 14:11:28 +08:00
nilaoda
82f2111522 update 2021-01-24 16:26:32 +08:00
nilaoda
4c3207586f Update MPDParser.cs 2021-01-24 16:24:03 +08:00
nilaoda
69b411e37c fix sub merge bug 2021-01-24 16:22:13 +08:00
nilaoda
1e8525041f Download from DSNP 2021-01-24 16:21:32 +08:00
nilaoda
65ae72d4a4 Update MPDParser.cs 2021-01-18 20:36:43 +08:00
nilaoda
4a4bfae5ab 优化MPD下载行为 2021-01-18 02:00:19 +08:00
nilaoda
d586dddfcd Update changelog.txt 2021-01-18 01:59:31 +08:00
nilaoda
fca6b3ff6c Update changelog.txt 2020-12-29 23:19:39 +08:00
nilaoda
5d75626a36 Update Global.cs 2020-12-29 23:18:16 +08:00
nilaoda
a94271c244 mpd - xigua 2020-12-20 18:53:40 +08:00
nilaoda
c51118dce7 解密huke88 2020-12-20 18:53:02 +08:00
nilaoda
81b2e87bf7 处理同一ID分散在不同Period的情况 2020-12-12 02:07:41 +08:00
nilaoda
71a9878aaa Update changelog.txt 2020-12-06 21:32:48 +08:00
nilaoda
769fe4e926 Update Global.cs 2020-12-06 21:32:38 +08:00
nilaoda
1f57ba7c09 Update Parser.cs 2020-12-06 21:32:29 +08:00
nilaoda
71282bda30 Update N_m3u8DL-CLI.csproj 2020-12-02 20:35:44 +08:00
nilaoda
41ee8aebdf update project 2020-12-02 20:31:44 +08:00
nilaoda
a4537bc093 del xml 2020-12-02 20:23:50 +08:00
nilaoda
b8a60b3917 Update packages.config 2020-12-02 20:23:36 +08:00
nilaoda
8091dd290f Update N_m3u8DL-CLI.csproj 2020-12-02 20:15:29 +08:00
nilaoda
d48e84e611 Update FodyWeavers.xml 2020-12-02 20:10:29 +08:00
nilaoda
9f5423a437 Costura.Fody 2020-12-02 19:56:20 +08:00
nilaoda
ce7e38770a Update N_m3u8DL-CLI.csproj 2020-12-02 19:51:29 +08:00
nilaoda
8fdb2e918e Update packages.config 2020-12-02 19:49:10 +08:00
nilaoda
d4b7d240c1 修正多语言识别问题 2020-12-02 11:56:46 +08:00
nilaoda
484d2941ed Update Global.cs 2020-12-02 11:56:17 +08:00
nilaoda
a0f2b66575 Update changelog.txt 2020-12-02 11:56:04 +08:00
nilaoda
65cc0681e2 Update changelog.txt 2020-11-26 21:02:04 +08:00
nilaoda
7d980ec9a2 Update Global.cs 2020-11-26 21:01:57 +08:00
nilaoda
ec5892c05a 修复可能存在的溢出问题 2020-11-26 21:01:48 +08:00
nilaoda
9aed50fbf9 优化MPD识别 2020-11-26 21:01:03 +08:00
nilaoda
d657b455cd BUG FIX 2020-11-25 21:16:41 +08:00
nilaoda
cda6575605 BUG FIX 2020-11-25 21:16:18 +08:00
nilaoda
0d6377d41b Update changelog.txt 2020-11-25 17:34:53 +08:00
nilaoda
9c76bdcbce 支持选择音轨 2020-11-25 17:34:12 +08:00
nilaoda
83915ff606 Update Global.cs 2020-11-25 14:12:46 +08:00
nilaoda
9cd4746f33 Update changelog.txt 2020-11-25 14:11:31 +08:00
nilaoda
33a5b917ac 修正MPD判断最高清晰度的逻辑 2020-11-25 14:08:40 +08:00
nilaoda
f69978bd82 修改芒果TV请求头 2020-11-23 21:53:41 +08:00
nilaoda
d9fd526886 Update changelog.txt 2020-11-23 21:53:26 +08:00
nilaoda
1cc8ecfaaf Update Global.cs 2020-11-23 21:30:12 +08:00
nilaoda
2bc2dde2ad 修改默认UA 2020-11-23 21:29:48 +08:00
nilaoda
c3ddcf9e0e Update Program.cs 2020-11-23 21:29:31 +08:00
nilaoda
ba5d20dd02 Update Parser.cs 2020-11-23 21:29:03 +08:00
nilaoda
16f705fe66 Update Global.cs 2020-11-22 23:13:59 +08:00
nilaoda
d141cabc4a Update changelog.txt 2020-11-22 23:08:51 +08:00
nilaoda
adcf884a93 新的任务监控逻辑 2020-11-22 23:08:33 +08:00
nilaoda
9d903a025f Update DownloadManager.cs 2020-11-22 22:36:21 +08:00
33 changed files with 1133 additions and 719 deletions

View File

@@ -31,4 +31,4 @@ jobs:
uses: actions/upload-artifact@v1.0.0
with:
name: N_m3u8DL-CLI_latest
path: N_m3u8DL-CLI\bin\Release\
path: N_m3u8DL-CLI\bin\Release\N_m3u8DL-CLI.exe

View File

@@ -0,0 +1,53 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
namespace N_m3u8DL_CLI
{
//https://js.huke88.com/assets/revision/js/plugins/tcplayer/tcplayer.v4.1.min.js?v=930
//https://js.huke88.com/assets/revision/js/plugins/tcplayer/libs/hls.min.0.13.2m.js?v=930
class DecodeHuke88Key
{
private static string[] GetOverlayInfo(string url)
{
var enc = new Regex("eyJ\\w{100,}").Match(url).Value;
var json = Encoding.UTF8.GetString(Convert.FromBase64String(enc));
JObject jObject = JObject.Parse(json);
var key = jObject["overlayKey"].ToString();
var iv = jObject["overlayIv"].ToString();
return new string[] { key, iv };
}
public static string DecodeKey(string url, byte[] data)
{
var info = GetOverlayInfo(url);
var overlayKey = info[0];
var overlayIv = info[1];
var l = new List<byte>();
var c = new List<byte>();
for (int h = 0; h < 16; h++)
{
var f = overlayKey.Substring(2 * h, 2);
var g = overlayIv.Substring(2 * h, 2);
l.Add(Convert.ToByte(f, 16));
c.Add(Convert.ToByte(g, 16));
}
var _lastCipherblock = c.ToArray();
var t = new byte[data.Length];
var r = data;
r = Decrypter.AES128Decrypt(data, l.ToArray(), Decrypter.HexStringToBytes("00000000000000000000000000000000"), CipherMode.CBC, PaddingMode.Zeros);
for (var o = 0; o < 16; o++)
t[o] = (byte)(r[o] ^ _lastCipherblock[o]);
var key = Convert.ToBase64String(t);
return key;
}
}
}

View File

@@ -1,16 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_CLI
{
class Decrypter
{
public static byte[] AES128Decrypt(string filePath, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC)
public static byte[] AES128Decrypt(string filePath, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
FileStream fs = new FileStream(filePath, FileMode.Open);
//获取文件大小
@@ -25,14 +21,14 @@ namespace N_m3u8DL_CLI
dcpt.Key = keyByte;
dcpt.IV = ivByte;
dcpt.Mode = mode;
dcpt.Padding = PaddingMode.PKCS7;
dcpt.Padding = padding;
ICryptoTransform cTransform = dcpt.CreateDecryptor();
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
return resultArray;
}
public static byte[] AES128Decrypt(byte[] encryptedBuff, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC)
public static byte[] AES128Decrypt(byte[] encryptedBuff, byte[] keyByte, byte[] ivByte, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
byte[] inBuff = encryptedBuff;
@@ -42,7 +38,7 @@ namespace N_m3u8DL_CLI
dcpt.Key = keyByte;
dcpt.IV = ivByte;
dcpt.Mode = mode;
dcpt.Padding = PaddingMode.PKCS7;
dcpt.Padding = padding;
ICryptoTransform cTransform = dcpt.CreateDecryptor();
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
@@ -56,7 +52,7 @@ namespace N_m3u8DL_CLI
return new byte[0];
}
if (hexStr.StartsWith("0x") || hexStr.StartsWith("0X"))
if (hexStr.StartsWith("0x") || hexStr.StartsWith("0X"))
{
hexStr = hexStr.Remove(0, 2);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,116 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_CLI
{
class IqJsonParser
{
public static string Parse(string downDir, string json)
{
JObject jObject = JObject.Parse(json);
var aClips = jObject["payload"]["wm_a"]["audio_track1"]["files"].Value<JArray>();
var vClips = jObject["payload"]["wm_a"]["video_track1"]["files"].Value<JArray>();
var codecsList = new List<string>();
var audioPath = "";
var videoPath = "";
var audioInitPath = "";
var videoInitPath = "";
if (aClips.Count > 0)
{
var init = jObject["payload"]["wm_a"]["audio_track1"]["codec_init"].Value<string>();
byte[] bytes = Convert.FromBase64String(init);
//输出init文件
audioInitPath = Path.Combine(downDir, "iqAudioInit.mp4");
File.WriteAllBytes(audioInitPath, bytes);
StringBuilder sb = new StringBuilder();
sb.AppendLine("#EXTM3U");
sb.AppendLine("#EXT-X-VERSION:3");
sb.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
sb.AppendLine("#CREATED-BY:N_m3u8DL-CLI");
sb.AppendLine($"#EXT-CODEC:{jObject["payload"]["wm_a"]["audio_track1"]["codec"].Value<string>()}");
sb.AppendLine($"#EXT-KID:{jObject["payload"]["wm_a"]["audio_track1"]["key_id"].Value<string>()}");
sb.AppendLine($"#EXT-X-MAP:URI=\"{new Uri(Path.Combine(downDir + "(Audio)", "iqAudioInit.mp4")).ToString()}\"");
sb.AppendLine("#EXT-X-KEY:METHOD=PLZ-KEEP-RAW,URI=\"None\"");
foreach (var a in aClips)
{
sb.AppendLine($"#EXTINF:{a["duration_second"].ToString()}");
sb.AppendLine(a["file_name"].Value<string>());
}
sb.AppendLine("#EXT-X-ENDLIST");
//输出m3u8文件
var _path = Path.Combine(downDir, "iqAudio.m3u8");
File.WriteAllText(_path, sb.ToString());
audioPath = new Uri(_path).ToString();
codecsList.Add(jObject["payload"]["wm_a"]["audio_track1"]["codec"].Value<string>());
}
if (vClips.Count > 0)
{
var init = jObject["payload"]["wm_a"]["video_track1"]["codec_init"].Value<string>();
byte[] bytes = Convert.FromBase64String(init);
//输出init文件
videoInitPath = Path.Combine(downDir, "iqVideoInit.mp4");
File.WriteAllBytes(videoInitPath, bytes);
StringBuilder sb = new StringBuilder();
sb.AppendLine("#EXTM3U");
sb.AppendLine("#EXT-X-VERSION:3");
sb.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD");
sb.AppendLine("#CREATED-BY:N_m3u8DL-CLI");
sb.AppendLine($"#EXT-CODEC:{jObject["payload"]["wm_a"]["video_track1"]["codec"].Value<string>()}");
sb.AppendLine($"#EXT-KID:{jObject["payload"]["wm_a"]["video_track1"]["key_id"].Value<string>()}");
sb.AppendLine($"#EXT-X-MAP:URI=\"{new Uri(videoInitPath).ToString()}\"");
sb.AppendLine("#EXT-X-KEY:METHOD=PLZ-KEEP-RAW,URI=\"None\"");
foreach (var a in vClips)
{
var start = a["seekable"]["pos_start"].Value<long>();
var size = a["size"].Value<long>();
sb.AppendLine($"#EXTINF:{a["duration_second"].ToString()}");
sb.AppendLine($"#EXT-X-BYTERANGE:{size}@{start}");
sb.AppendLine(a["file_name"].Value<string>());
}
sb.AppendLine("#EXT-X-ENDLIST");
//输出m3u8文件
var _path = Path.Combine(downDir, "iqVideo.m3u8");
File.WriteAllText(_path, sb.ToString());
videoPath = new Uri(_path).ToString();
codecsList.Add(jObject["payload"]["wm_a"]["video_track1"]["codec"].Value<string>());
}
var content = "";
if ((videoPath == "" && audioPath != "") || Global.VIDEO_TYPE == "IGNORE")
{
return audioPath;
}
else if (audioPath == "" && videoPath != "")
{
return videoPath;
}
else
{
if (!Directory.Exists(downDir + "(Audio)"))
Directory.CreateDirectory(downDir + "(Audio)");
var _path = Path.Combine(downDir + "(Audio)", "iqAudio.m3u8");
var _pathInit = Path.Combine(downDir + "(Audio)", "iqAudioInit.mp4");
File.Copy(new Uri(audioPath).LocalPath, _path, true);
File.Copy(new Uri(audioInitPath).LocalPath, _pathInit, true);
audioPath = new Uri(_path).ToString();
content = $"#EXTM3U\r\n" +
$"#EXT-X-MEDIA:TYPE=AUDIO,URI=\"{audioPath}\",GROUP-ID=\"default-audio-group\",NAME=\"stream_0\",AUTOSELECT=YES,CHANNELS=\"0\"\r\n" +
$"#EXT-X-STREAM-INF:BANDWIDTH=99999,CODECS=\"{string.Join(",", codecsList)}\",RESOLUTION=0x0,AUDIO=\"default-audio-group\"\r\n" +
$"{videoPath}";
}
var _masterPath = Path.Combine(downDir, "master.m3u8");
File.WriteAllText(_masterPath, content);
return new Uri(_masterPath).ToString();
}
}
}

View File

@@ -11,8 +11,6 @@ namespace N_m3u8DL_CLI
{
class LOGGER
{
public static int CursorIndex = 5;
public static int FFmpegCorsorIndex = 5;
public const int Default = 1;
public const int Error = 2;
public const int Warning = 3;
@@ -36,8 +34,13 @@ namespace N_m3u8DL_CLI
{
if (!Directory.Exists(Path.GetDirectoryName(LOGFILE)))//若文件夹不存在则新建文件夹
Directory.CreateDirectory(Path.GetDirectoryName(LOGFILE)); //新建文件夹
if (File.Exists(LOGFILE))//若文件存在则删除
File.Delete(LOGFILE);
//若文件存在则加序号
int index = 1;
var fileName = Path.GetFileNameWithoutExtension(LOGFILE);
while (File.Exists(LOGFILE))
{
LOGFILE = Path.Combine(Path.GetDirectoryName(LOGFILE), $"{fileName}-{index++}.log");
}
string file = LOGFILE;
string now = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
string init = "LOG " + DateTime.Now.ToString("yyyy/MM/dd") + "\r\n"
@@ -57,40 +60,28 @@ namespace N_m3u8DL_CLI
//读写锁机制,当资源被占用,其他线程等待
static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
public static void PrintLine(string text, int printLevel = 1, int cursorIndex = 0)
public static void PrintLine(string text, int printLevel = 1)
{
try
{
if (CursorIndex > 1000)
{
Console.Clear();
CursorIndex = 0;
}
if (cursorIndex == 0)
Console.SetCursorPosition(0, CursorIndex++);
else
Console.SetCursorPosition(0, cursorIndex);
}
catch (Exception)
{
;
}
switch (printLevel)
{
case 0:
Console.Write("\r" + new string(' ', Console.WindowWidth - 1) + "\r");
Console.WriteLine(" ".PadRight(12) + " " + text);
break;
case 1:
Console.Write("\r" + new string(' ', Console.WindowWidth - 1) + "\r");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
Console.WriteLine(text);
break;
case 2:
Console.Write("\r" + new string(' ', Console.WindowWidth - 1) + "\r");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(text);
Console.ResetColor();
break;
case 3:
Console.Write("\r" + new string(' ', Console.WindowWidth - 1) + "\r");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(text);
@@ -118,7 +109,7 @@ namespace N_m3u8DL_CLI
}
catch (Exception)
{
}
finally
{
@@ -143,7 +134,7 @@ namespace N_m3u8DL_CLI
}
catch (Exception)
{
}
finally
{
@@ -156,7 +147,7 @@ namespace N_m3u8DL_CLI
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(DateTime.Now.ToString("o") + " " + text);
while (Console.ForegroundColor == ConsoleColor.Red)
while (Console.ForegroundColor == ConsoleColor.Red)
Console.ResetColor();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" />
<Import Project="..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props" Condition="Exists('..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +14,8 @@
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
@@ -38,6 +42,14 @@
<ApplicationIcon>logo_3Iv_icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="BrotliSharpLib, Version=0.3.2.0, Culture=neutral, PublicKeyToken=3f4e2a1cd615fcb7, processorArchitecture=MSIL">
<HintPath>..\packages\BrotliSharpLib.0.3.3\lib\net451\BrotliSharpLib.dll</HintPath>
</Reference>
<Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>..\packages\Costura.Fody.4.1.0\lib\net40\Costura.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.Build.Utilities.v4.0" />
<Reference Include="Microsoft.JScript" />
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@@ -51,6 +63,9 @@
<Reference Include="System.Collections" />
<Reference Include="System.Core" />
<Reference Include="System.IO" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -64,6 +79,7 @@
<Compile Include="CommandLineArgumentParser.cs" />
<Compile Include="Decode51CtoKey.cs" />
<Compile Include="DecodeDdyun.cs" />
<Compile Include="DecodeHuke88Key.cs" />
<Compile Include="DecodeImooc.cs" />
<Compile Include="DecodeNfmovies.cs" />
<Compile Include="Decrypter.cs" />
@@ -71,11 +87,13 @@
<Compile Include="Global.cs" />
<Compile Include="HLSLiveDownloader.cs" />
<Compile Include="HLSTags.cs" />
<Compile Include="IqJsonParser.cs" />
<Compile Include="LOGGER.cs" />
<Compile Include="DownloadManager.cs" />
<Compile Include="MPDParser.cs" />
<Compile Include="Parser.cs" />
<Compile Include="Program.cs" />
<Compile Include="ProgressReporter.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Downloader.cs" />
<Compile Include="strings.Designer.cs">
@@ -130,4 +148,13 @@
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props'))" />
<Error Condition="!Exists('..\packages\Fody.6.0.0\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.6.0.0\build\Fody.targets'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props'))" />
</Target>
<Import Project="..\packages\Fody.6.0.0\build\Fody.targets" Condition="Exists('..\packages\Fody.6.0.0\build\Fody.targets')" />
</Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_CLI
{
class ProgressReporter
{
private static string speed = "";
private static string progress = "";
static object lockThis = new object();
public static void Report(string progress, string speed)
{
lock (lockThis)
{
if (!string.IsNullOrEmpty(progress)) ProgressReporter.progress = progress;
if (!string.IsNullOrEmpty(speed)) ProgressReporter.speed = speed;
string now = DateTime.Now.ToString("HH:mm:ss.000");
var sub = Console.WindowWidth - 4 - ProgressReporter.progress.Length - ProgressReporter.speed.Length - now.Length;
if (sub <= 0) sub = 0;
string print = now + " " + ProgressReporter.progress + " " + ProgressReporter.speed + new string(' ', sub);
Console.Write("\r" + print + "\r");
//Console.Write(print);
}
}
}
}

View File

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nilaoda")]
[assembly: AssemblyProduct("N_m3u8DL-CLI")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
// 方法是按如下所示使用“*”: :
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("2.7.0.0")]
[assembly: AssemblyVersion("2.9.9.0")]
[assembly: AssemblyFileVersion("2.9.9.0")]

View File

@@ -59,10 +59,12 @@ namespace N_m3u8DL_CLI
//Console.Title = Now + " / " + Total;
string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
int padding = downloadedSize.Length > estimatedSize.Length ? downloadedSize.Length : estimatedSize.Length;
DownloadManager.ToDoSize = (DownloadManager.DownloadedSize * total / now) - DownloadManager.DownloadedSize;
string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
Console.SetCursorPosition(0, 2);
Console.Write(("Progress: " + Now + " of " + Total
+ $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
var print = "Progress: " + Now + "/" + Total
+ $" ({percent}) -- {downloadedSize.PadLeft(padding)}/{estimatedSize.PadRight(padding)}";
ProgressReporter.Report(print, "");
}
private void OnRenamed(object source, RenamedEventArgs e)
@@ -77,10 +79,12 @@ namespace N_m3u8DL_CLI
//Console.Title = Now + " / " + Total;
string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
int padding = downloadedSize.Length > estimatedSize.Length ? downloadedSize.Length : estimatedSize.Length;
DownloadManager.ToDoSize = (DownloadManager.DownloadedSize * total / now) - DownloadManager.DownloadedSize;
string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
Console.SetCursorPosition(0, 2);
Console.Write(("Progress: " + Now + " of " + Total
+ $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
var print = "Progress: " + Now + "/" + Total
+ $" ({percent}) -- {downloadedSize.PadLeft(padding)}/{estimatedSize.PadRight(padding)}";
ProgressReporter.Report(print, "");
}
private void OnDeleted(object source, FileSystemEventArgs e)
@@ -95,10 +99,12 @@ namespace N_m3u8DL_CLI
//Console.Title = Now + " / " + Total;
string downloadedSize = Global.FormatFileSize(DownloadManager.DownloadedSize);
string estimatedSize = Global.FormatFileSize(DownloadManager.DownloadedSize * total / now);
int padding = downloadedSize.Length > estimatedSize.Length ? downloadedSize.Length : estimatedSize.Length;
DownloadManager.ToDoSize = (DownloadManager.DownloadedSize * total / now) - DownloadManager.DownloadedSize;
string percent = (Convert.ToDouble(now) / Convert.ToDouble(total) * 100).ToString("0.00") + "%";
Console.SetCursorPosition(0, 2);
Console.Write(("Progress: " + Now + " of " + Total
+ $" ({percent}/{downloadedSize}/{estimatedSize}/{Global.FormatTime(Convert.ToInt32(TotalDuration))})").PadRight(62));
var print = "Progress: " + Now + "/" + Total
+ $" ({percent}) -- {downloadedSize.PadLeft(padding)}/{estimatedSize.PadRight(padding)}";
ProgressReporter.Report(print, "");
}
}
}

View File

@@ -286,4 +286,77 @@
- GIF HEADER检测
- 修复BUG
2020年11月22日
- 解决HTTPS协议自动重定向后Referer丢失问题
- 解决HTTPS协议自动重定向后Referer丢失问题
- 新的任务速度监控逻辑
2020年11月23日
- 将默认UA修改为 Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
- 修改芒果TV请求头
2020年11月25日
- 修正MPD判断最高清晰度的逻辑
- 在MPD输入下支持选择音轨
- 修复BUG
2020年11月26日
- 优化MPD识别方案
- 修复MPD情况下时间戳溢出问题
2020年12月2日
- FIX Language Bug
2020年12月6日
- 使用手机UA请求气球云密钥服务器
2020年12月12日
- 修复MPD下同一个ID分散在不同Period导致下载不完全问题
2020年12月20日
- 支持解密虎课网
2021年1月18日
- 完善MPD下载相关
- 重新打包多语言资源
2021年1月24日
- 适配Disney+资源
- MPD选择流行为优化
- 修复二进制合并时vtt字幕被合并为ts后缀问题
2021年2月1日
- 修正自定义KEY且存在IV时的隐患
- 优化跳过PNG Header的算法
2021年2月2日
- 独播库自动加入referer
- 修复气球云
2021年2月10日
- 修正MPD拼接BaseUrl逻辑
2021年2月11日
- 将CNTV视频修改为未加密链接
2021年2月21日
- MPD检测最后一个分片是否有效
2021年2月22日
- 添加用户网络代理支持,使用--proxyAddress指定代理地址。@evanlabs
2021年3月3日
- 修复M3U8选择音轨/字幕不生效问题
- 外挂音轨时enableAudioOnly可仅下载音频
- 移除气球云支持
2021年3月15日
- 修复enableAudioOnly且下载MPD文件时留下冗余(Audio)文件夹的情况
2021年3月22日
- 适配AppleTv资源
2021年3月25日
- 优化下载监控
- 为下载分片增加了自动重试机制(3次)
2021年3月27日
- 优化显示输出
- 增加ETA显示
2021年6月27日
- 修正判断png图片时可能出现的数组越界bug
- 支持解压brotli测试地址 https://www.baobuzz.com/m3u8/236963.m3u8?sign=811ae52382b7dd1d247f705e1bcaddf4
2021年7月4日
- 优化master选择最高清晰度逻辑大于改为大于等于
- 支持爱奇艺DRM-JSON自动转换为m3u8
2021年8月15日
- 优化显示输出
- 强校验MAP下载成功
2021年9月5日
- 修复MPD节点选择BUG
- 修复速度输出padding负值问题
- 修复同一个period且同id导致被重复添加分片
- 优化AppleTV判断
2021年10月19日
- 修复选择清晰度在输入选项后界面异常问题
- 修复日志冲突问题
2021年11月12日
- 修复init url缺失baseurl问题

View File

@@ -1,5 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BrotliSharpLib" version="0.3.3" targetFramework="net46" />
<package id="Costura.Fody" version="4.1.0" targetFramework="net46" />
<package id="Fody" version="6.0.0" targetFramework="net46" developmentDependency="true" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
<package id="NiL.JS" version="2.5.1428" targetFramework="net46" />
<package id="Resource.Embedder" version="2.1.1" targetFramework="net46" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net46" />
</packages>

View File

@@ -47,8 +47,8 @@ namespace N_m3u8DL_CLI {
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性
/// 重写当前线程的 CurrentUICulture 属性
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
@@ -69,6 +69,15 @@ namespace N_m3u8DL_CLI {
}
}
/// <summary>
/// 查找类似 正在判断尾分片是否有效... 的本地化字符串。
/// </summary>
internal static string checkingLast {
get {
return ResourceManager.GetString("checkingLast", resourceCulture);
}
}
/// <summary>
/// 查找类似 已关闭完整性检查 的本地化字符串。
/// </summary>
@@ -493,6 +502,15 @@ namespace N_m3u8DL_CLI {
}
}
/// <summary>
/// 查找类似 开始解析MPD内容... 的本地化字符串。
/// </summary>
internal static string startParsingMpd {
get {
return ResourceManager.GetString("startParsingMpd", resourceCulture);
}
}
/// <summary>
/// 查找类似 重新解析m3u8... 的本地化字符串。
/// </summary>

View File

@@ -201,6 +201,7 @@
--downloadRange Range Set range for a video
--stopSpeed Number Speed below this, retry(KB/s)
--maxSpeed Number Set max download speed(KB/s)
--proxyAddress http://xx Set HTTP Proxy, like http://127.0.0.1:8080
--enableDelAfterDone Enable delete clips after download completed
--enableMuxFastStart Enable fast start for mp4
--enableBinaryMerge Enable use binary merge instead ffmpeg
@@ -298,4 +299,10 @@
<data name="wrtingMeta" xml:space="preserve">
<value>Writing Json: [meta.json]</value>
</data>
<data name="startParsingMpd" xml:space="preserve">
<value>Start Parsing MPD Content...</value>
</data>
<data name="checkingLast" xml:space="preserve">
<value>Checking Whether The Last Fragment Is Valid...</value>
</data>
</root>

View File

@@ -202,6 +202,7 @@
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
--maxSpeed Number 设置下载速度上限(单位为KB/s)
--proxyAddress http://xx 设置HTTP代理, 如 http://127.0.0.1:8080
--enableDelAfterDone 开启下载后删除临时文件夹的功能
--enableMuxFastStart 开启混流mp4的FastStart特性
--enableBinaryMerge 开启二进制合并分片
@@ -299,4 +300,10 @@
<data name="wrtingMeta" xml:space="preserve">
<value>写出meta.json</value>
</data>
<data name="startParsingMpd" xml:space="preserve">
<value>开始解析MPD内容...</value>
</data>
<data name="checkingLast" xml:space="preserve">
<value>正在判断尾分片是否有效...</value>
</data>
</root>

View File

@@ -202,6 +202,7 @@
--liveRecDur HH:MM:SS 直播錄制時,達到此長度自動退出軟件
--stopSpeed Number 當速度低於此值時,重試(單位為KB/s)
--maxSpeed Number 設置下載速度上限(單位為KB/s)
--proxyAddress http://xx 設置HTTP代理, 如 http://127.0.0.1:8080
--enableDelAfterDone 開啟下載後刪除臨時文件夾的功能
--enableMuxFastStart 開啟混流mp4的FastStart特性
--enableBinaryMerge 開啟二進制合並分片
@@ -299,4 +300,10 @@
<data name="wrtingMeta" xml:space="preserve">
<value>寫出meta.json</value>
</data>
<data name="startParsingMpd" xml:space="preserve">
<value>開始解析MPD內容...</value>
</data>
<data name="checkingLast" xml:space="preserve">
<value>正在判斷尾分片是否有效...</value>
</data>
</root>

View File

@@ -13,20 +13,23 @@
# [ENGLISH VERSION](https://github.com/nilaoda/N_m3u8DL-CLI/blob/master/README_ENG.md)
# 下载使用
* 发行版: https://github.com/nilaoda/N_m3u8DL-CLI/releases
* 自动构建版`(供测试)`: https://github.com/nilaoda/N_m3u8DL-CLI/actions
# 关于开源
本项目已2019年10月9日开源采用MIT许可证各取所需。
本项目已2019年10月9日开源采用MIT许可证各取所需。
# 关于跨平台
~~本项目已通过`.NET Core`实现跨平台理论支持Mac、Linux、Windows等平台请移步https://github.com/nilaoda/N_m3u8DL-CLI_Core~~
暂时放弃跨平台很多API需要重写才能实现功能日后有空再维护
搁置了
# N_m3u8DL-CLI
一个**简单易用的**m3u8下载器下载地址https://github.com/nilaoda/N_m3u8DL-CLI/releases
支持下载m3u8链接或文件为`mp4`或`ts`格式,并提供丰富的命令行选项。
* **不支持**优酷视频解密
* **不支持**气球云视频解密
* 支持`AES-128-CBC`加密自动解密
* 支持多线程下载
* 支持下载限速
@@ -39,7 +42,8 @@
* 支持下载路径为网络驱动器的情况
* 支持下载外挂字幕轨道、音频轨道
* 支持仅合并为音频
* 自动使用系统代理(可禁止)
* 支持设置特定http代理
* 支持自动使用系统代理(默认行为, 可禁止)
* 提供SimpleG简易的`GUI`生成常用参数
@@ -48,7 +52,7 @@
# 命令行选项
```
N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS]
--workDir Directory 设定程序工作目录
--saveName Filename 设定存储文件名(不包括后缀)
@@ -66,6 +70,7 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
--maxSpeed Number 设置下载速度上限(单位为KB/s)
--proxyAddress http://xx 设置HTTP代理, 如 http://127.0.0.1:8080
--enableDelAfterDone 开启下载后删除临时文件夹的功能
--enableMuxFastStart 开启混流mp4的FastStart特性
--enableBinaryMerge 开启二进制合并分片
@@ -80,5 +85,8 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
# 用户文档
https://nilaoda.github.io/N_m3u8DL-CLI/
# 聊聊
https://discord.gg/W5tvcRJDPs
# 赞赏
https://nilaoda.github.io/N_m3u8DL-CLI/source/images/alipay.png
![Wow](https://nilaoda.github.io/N_m3u8DL-CLI/source/images/alipay.png)

View File

@@ -8,10 +8,10 @@
╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚════╝ ╚═════╝ ╚══════╝ ╚═════╝╚══════╝╚═╝
```
This is a m3u8 downloader.
This is an m3u8 downloader.
## Summary
Supports:
* Auto deceypt for `AES-128-CBC`
* Auto decrypt for `AES-128-CBC`
* `Master List`
* Live stream recording(`BETA`)
* Customize HTTP headers
@@ -20,8 +20,8 @@ Supports:
* Network driver on Windows OS
* Alternative audio/video track
* Mux without video track
* Auto use system proxy
* Optimization for Chinese streaming platform
* Custom HTTP proxy or Use system proxy
* Optimization for Chinese streaming platforms
![ScreenShot](https://nilaoda.github.io/N_m3u8DL-CLI/source/images/%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8.gif)
@@ -47,9 +47,10 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
--downloadRange Range Set range for a video
--stopSpeed Number Speed below this, retry(KB/s)
--maxSpeed Number Set max download speed(KB/s)
--proxyAddress http://xx Set HTTP Proxy, like http://127.0.0.1:8080
--enableDelAfterDone Enable delete clips after download completed
--enableMuxFastStart Enable fast start for mp4
--enableBinaryMerge Enable use binary merge instead ffmpeg
--enableBinaryMerge Enable use binary merge instead of ffmpeg
--enableParseOnly Enable parse mode
--enableAudioOnly Enable only audio track when mux use ffmpeg
--disableDateInfo Disable write date info when mux use ffmpeg
@@ -60,3 +61,6 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
## Document
https://nilaoda.github.io/N_m3u8DL-CLI/
## Chit-chat
https://discord.gg/W5tvcRJDPs

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More