You've already forked N_m3u8DL-CLI
mirror of
https://github.com/nilaoda/N_m3u8DL-CLI
synced 2025-09-10 12:40:52 +02:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c2e13b800 | ||
![]() |
086fc57958 | ||
![]() |
bc349b8977 | ||
![]() |
cc4efed3c6 | ||
![]() |
cf958e833b | ||
![]() |
fb09add0cd | ||
![]() |
5a3c5baefd | ||
![]() |
839afd8e61 | ||
![]() |
338c7a25d0 | ||
![]() |
f57ce8c2da | ||
![]() |
a5009e1683 | ||
![]() |
66933da9de | ||
![]() |
136389e248 |
@@ -15,6 +15,7 @@ namespace N_m3u8DL_CLI
|
||||
private int stopCount = 0; //速度为零的停止
|
||||
private int timeOut = 10000; //超时设置
|
||||
private static double downloadedSize = 0; //已下载大小
|
||||
private static bool disableIntegrityCheck = false; //关闭完整性检查
|
||||
|
||||
private string jsonFile = string.Empty;
|
||||
private string headers = string.Empty;
|
||||
@@ -58,6 +59,7 @@ namespace N_m3u8DL_CLI
|
||||
public static int CalcTime { get => calcTime; set => calcTime = value; }
|
||||
public static int Count { get => count; set => count = value; }
|
||||
public static int PartsCount { get => partsCount; set => partsCount = value; }
|
||||
public static bool DisableIntegrityCheck { get => disableIntegrityCheck; set => disableIntegrityCheck = value; }
|
||||
|
||||
public void DoDownload()
|
||||
{
|
||||
@@ -150,6 +152,7 @@ namespace N_m3u8DL_CLI
|
||||
//开始调用下载
|
||||
LOGGER.WriteLine("Start Downloading");
|
||||
LOGGER.PrintLine("开始下载文件", LOGGER.Warning);
|
||||
|
||||
//下载MAP文件(若有)
|
||||
try
|
||||
{
|
||||
@@ -223,6 +226,8 @@ namespace N_m3u8DL_CLI
|
||||
if (Global.HadReadInfo == false)
|
||||
{
|
||||
string href = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value<int>().ToString(segsPadZero) + ".ts";
|
||||
if (File.Exists(DownDir + "\\!MAP.ts"))
|
||||
href = DownDir + "\\!MAP.ts";
|
||||
Global.GzipHandler(href);
|
||||
bool flag = false;
|
||||
foreach (string ss in (string[])Global.GetVideoInfo(href).ToArray(typeof(string)))
|
||||
@@ -335,11 +340,19 @@ namespace N_m3u8DL_CLI
|
||||
public void IsComplete(int segCount)
|
||||
{
|
||||
int tsCount = 0;
|
||||
|
||||
if (DisableIntegrityCheck)
|
||||
{
|
||||
tsCount = segCount;
|
||||
goto ll;
|
||||
}
|
||||
|
||||
for (int i = 0; i < PartsCount; i++)
|
||||
{
|
||||
tsCount += Global.GetFileCount(DownDir + "\\Part_" + i.ToString(partsPadZero), ".ts");
|
||||
}
|
||||
|
||||
ll:
|
||||
if (tsCount != segCount)
|
||||
{
|
||||
LOGGER.PrintLine("完成数量 " + tsCount + " / " + segCount);
|
||||
@@ -356,7 +369,7 @@ namespace N_m3u8DL_CLI
|
||||
}
|
||||
else //开始合并
|
||||
{
|
||||
LOGGER.PrintLine("已下载完毕");
|
||||
LOGGER.PrintLine("已下载完毕" + (DisableIntegrityCheck ? "(已关闭完整性检查)" : ""));
|
||||
Console.WriteLine();
|
||||
if (NoMerge == false)
|
||||
{
|
||||
@@ -511,7 +524,7 @@ namespace N_m3u8DL_CLI
|
||||
|
||||
FFmpeg.OutPutPath = Path.Combine(Directory.GetParent(DownDir).FullName, DownName);
|
||||
FFmpeg.ReportFile = driverName + "\\:" + exePath.Remove(0, exePath.IndexOf(':') + 1).Replace("\\", "/") + "/Logs/" + Path.GetFileNameWithoutExtension(LOGGER.LOGFILE) + fflogName;
|
||||
|
||||
|
||||
//合并分段
|
||||
LOGGER.PrintLine("合并分段中...");
|
||||
for (int i = 0; i < PartsCount; i++)
|
||||
@@ -560,7 +573,7 @@ namespace N_m3u8DL_CLI
|
||||
FFmpeg.Merge(Global.GetFiles(DownDir, ".ts"), MuxFormat, MuxFastStart);
|
||||
else
|
||||
{
|
||||
JObject json = JObject.Parse(MuxSetJson);
|
||||
JObject json = JObject.Parse(File.ReadAllText(MuxSetJson, Encoding.UTF8));
|
||||
string muxFormat = json["muxFormat"].Value<string>();
|
||||
bool fastStart = Convert.ToBoolean(json["fastStart"].Value<string>());
|
||||
string poster = json["poster"].Value<string>();
|
||||
|
@@ -30,8 +30,8 @@ namespace N_m3u8DL_CLI
|
||||
|
||||
|
||||
/*===============================================================================*/
|
||||
static string nowVer = "2.3.3";
|
||||
static string nowDate = "20191007";
|
||||
static string nowVer = "2.4.4";
|
||||
static string nowDate = "20191218";
|
||||
public static void WriteInit()
|
||||
{
|
||||
Console.Clear();
|
||||
@@ -58,7 +58,10 @@ namespace N_m3u8DL_CLI
|
||||
//尝试下载新版本(去码云)
|
||||
string url = $"https://gitee.com/nilaoda/N_m3u8DL-CLI/raw/master/N_m3u8DL-CLI_v{latestVer}.exe";
|
||||
if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), $"N_m3u8DL-CLI_v{latestVer}.exe")))
|
||||
{
|
||||
Console.Title = $"检测到更新,版本:{latestVer}! 新版下载成功,请您自行替换";
|
||||
return;
|
||||
}
|
||||
HttpDownloadFile(url, Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), $"N_m3u8DL-CLI_v{latestVer}.exe"));
|
||||
if (File.Exists(Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName), $"N_m3u8DL-CLI_v{latestVer}.exe")))
|
||||
Console.Title = $"检测到更新,版本:{latestVer}! 新版下载成功,请您自行替换";
|
||||
@@ -77,6 +80,16 @@ namespace N_m3u8DL_CLI
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetValidFileName(string input, string re = ".")
|
||||
{
|
||||
string title = input;
|
||||
foreach (char invalidChar in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
title = title.Replace(invalidChar.ToString(), re);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
// parseInt(s, radix)
|
||||
public static int GetNum(string str, int numBase)
|
||||
{
|
||||
@@ -100,7 +113,8 @@ namespace N_m3u8DL_CLI
|
||||
if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
||||
{
|
||||
webRequest.UserAgent = "";
|
||||
webRequest.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
|
||||
if (!url.Contains("/internettv/"))
|
||||
webRequest.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
|
||||
webRequest.Headers.Add("Cookie", "MQGUID");
|
||||
}
|
||||
//添加headers
|
||||
@@ -482,7 +496,8 @@ namespace N_m3u8DL_CLI
|
||||
else if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
||||
{
|
||||
request.UserAgent = "";
|
||||
request.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
|
||||
if (!url.Contains("/internettv/"))
|
||||
request.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
|
||||
request.Headers.Add("Cookie", "MQGUID");
|
||||
}
|
||||
else
|
||||
@@ -697,6 +712,14 @@ namespace N_m3u8DL_CLI
|
||||
{
|
||||
VIDEO_TYPE = "DV";
|
||||
}
|
||||
else if (res.Contains("Video hevc (Main 10) (dvh1")) //优酷视频杜比视界
|
||||
{
|
||||
VIDEO_TYPE = "DV";
|
||||
}
|
||||
else if (res.Contains("Video hevc (dvh1")) //优酷视频杜比视界
|
||||
{
|
||||
VIDEO_TYPE = "DV";
|
||||
}
|
||||
else if (res.Contains("Video h264"))
|
||||
{
|
||||
VIDEO_TYPE = "H264";
|
||||
|
@@ -39,9 +39,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.JScript" />
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\..\HDC上传助手\HDC上传助手\bin\Debug\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections" />
|
||||
|
@@ -27,6 +27,8 @@ namespace N_m3u8DL_CLI
|
||||
private string m3u8Url = string.Empty;
|
||||
private string downDir = string.Empty;
|
||||
private string downName = string.Empty;
|
||||
private string keyFile = string.Empty;
|
||||
private string keyBase64 = string.Empty;
|
||||
private long bestBandwidth = 0;
|
||||
private string bestUrl = string.Empty;
|
||||
private string bestUrlAudio = string.Empty;
|
||||
@@ -46,6 +48,8 @@ namespace N_m3u8DL_CLI
|
||||
private static string durEnd = "";
|
||||
//是否自动清除优酷广告分片
|
||||
private static bool delAd = true;
|
||||
//标记是否已清除优酷广告分片
|
||||
private static bool hasAd = false;
|
||||
|
||||
public string BaseUrl { get => baseUrl; set => baseUrl = value; }
|
||||
public string M3u8Url { get => m3u8Url; set => m3u8Url = value; }
|
||||
@@ -57,6 +61,8 @@ namespace N_m3u8DL_CLI
|
||||
public static bool DelAd { get => delAd; set => delAd = value; }
|
||||
public static string DurStart { get => durStart; set => durStart = value; }
|
||||
public static string DurEnd { get => durEnd; set => durEnd = value; }
|
||||
public string KeyFile { get => keyFile; set => keyFile = value; }
|
||||
public string KeyBase64 { get => keyBase64; set => keyBase64 = value; }
|
||||
|
||||
public void Parse()
|
||||
{
|
||||
@@ -110,10 +116,28 @@ namespace N_m3u8DL_CLI
|
||||
|
||||
//如果BaseUrl为空则截取字符串充当
|
||||
if (BaseUrl == "")
|
||||
BaseUrl = GetBaseUrl(M3u8Url, headers);
|
||||
{
|
||||
if (new Regex("#YUMING\\|(.*)").IsMatch(m3u8Content))
|
||||
BaseUrl = new Regex("#YUMING\\|(.*)").Match(m3u8Content).Groups[1].Value;
|
||||
else
|
||||
BaseUrl = GetBaseUrl(M3u8Url, headers);
|
||||
}
|
||||
|
||||
LOGGER.WriteLine("Parsing Content");
|
||||
LOGGER.PrintLine("解析m3u8内容");
|
||||
|
||||
if (!string.IsNullOrEmpty(keyBase64))
|
||||
{
|
||||
string line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"base64:{keyBase64}\"";
|
||||
m3u8CurrentKey = ParseKey(line);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(keyFile))
|
||||
{
|
||||
Uri u = new Uri(keyFile);
|
||||
string line = $"#EXT-X-KEY:METHOD=AES-128,URI=\"{u.ToString()}\"";
|
||||
m3u8CurrentKey = ParseKey(line);
|
||||
}
|
||||
|
||||
//逐行分析
|
||||
using (StringReader sr = new StringReader(m3u8Content))
|
||||
{
|
||||
@@ -180,7 +204,16 @@ namespace N_m3u8DL_CLI
|
||||
//解析不连续标记,需要单独合并(timestamp不同)
|
||||
else if (line.StartsWith(HLSTags.ext_x_discontinuity))
|
||||
{
|
||||
if (segments.Count > 1)
|
||||
//修复优酷去除广告后的遗留问题
|
||||
if (hasAd && parts.Count > 0)
|
||||
{
|
||||
segments = (JArray)parts[parts.Count - 1];
|
||||
parts.RemoveAt(parts.Count - 1);
|
||||
hasAd = false;
|
||||
continue;
|
||||
}
|
||||
//常规情况的#EXT-X-DISCONTINUITY标记,新建part
|
||||
if (!hasAd && segments.Count > 1)
|
||||
{
|
||||
parts.Add(segments);
|
||||
segments = new JArray();
|
||||
@@ -192,7 +225,7 @@ namespace N_m3u8DL_CLI
|
||||
else if (line.StartsWith(HLSTags.ext_x_version)) ;
|
||||
else if (line.StartsWith(HLSTags.ext_x_allow_cache)) ;
|
||||
//解析KEY
|
||||
else if (line.StartsWith(HLSTags.ext_x_key))
|
||||
else if (line.StartsWith(HLSTags.ext_x_key) && string.IsNullOrEmpty(keyFile) && string.IsNullOrEmpty(keyBase64))
|
||||
{
|
||||
m3u8CurrentKey = ParseKey(line);
|
||||
//存储为上一行的key信息
|
||||
@@ -257,7 +290,8 @@ namespace N_m3u8DL_CLI
|
||||
//m3u8主体结束
|
||||
else if (line.StartsWith(HLSTags.ext_x_endlist))
|
||||
{
|
||||
parts.Add(segments);
|
||||
if (segments.Count > 0)
|
||||
parts.Add(segments);
|
||||
segments = new JArray();
|
||||
isEndlist = true;
|
||||
}
|
||||
@@ -286,10 +320,20 @@ namespace N_m3u8DL_CLI
|
||||
segments.Add(segInfo);
|
||||
segInfo = new JObject();
|
||||
//优酷的广告分段则清除此分片
|
||||
if (DelAd && segUrl.Contains("ccode") && segUrl.Contains("/ad/") && segUrl.Contains("duration"))
|
||||
//需要注意,遇到广告说明程序对上文的#EXT-X-DISCONTINUITY做出的动作是不必要的,
|
||||
//其实上下文是同一种编码,需要恢复到原先的part上
|
||||
if (DelAd && segUrl.Contains("ccode=") && segUrl.Contains("/ad/") && segUrl.Contains("duration="))
|
||||
{
|
||||
segments.RemoveAt(segments.Count - 1);
|
||||
segIndex--;
|
||||
hasAd = true;
|
||||
}
|
||||
//优酷广告(4K分辨率测试)
|
||||
if (DelAd && segUrl.Contains("ccode=0902") && segUrl.Contains("duration="))
|
||||
{
|
||||
segments.RemoveAt(segments.Count - 1);
|
||||
segIndex--;
|
||||
hasAd = true;
|
||||
}
|
||||
expectSegment = false;
|
||||
}
|
||||
|
@@ -197,6 +197,21 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
/// 2019年10月5日
|
||||
/// - N_m3u8DL-CLI.args.txt
|
||||
/// - 细节优化
|
||||
/// 2019年10月18日
|
||||
/// - 去掉了优酷DRM设备参数更改
|
||||
/// 2019年10月23日
|
||||
/// - 增加disableIntegrityCheck选项
|
||||
/// 2019年10月24日
|
||||
/// - 捕获Ctrl+C退出,移动光标到正确位置
|
||||
/// 2019年11月30日
|
||||
/// - 完善芒果TV请求头的自动添加
|
||||
/// 2019年12月16日
|
||||
/// - 处理文件名特殊字符
|
||||
/// 2019年12月18日
|
||||
/// - 修复m3u8解析bug导致的无法合并问题
|
||||
/// - 增加杜比视界识别场景
|
||||
/// - 修复part大于1时读取json混流文件的严重错误
|
||||
/// - 自动去除优酷的广告分片及前情提要
|
||||
/// </summary>
|
||||
///
|
||||
|
||||
@@ -214,11 +229,13 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
LOGGER.WriteLine("Exited: Ctrl + C"
|
||||
+ "\r\n\r\nTask End: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); //Ctrl+C关闭
|
||||
Console.CursorVisible = true;
|
||||
Console.SetCursorPosition(0, LOGGER.CursorIndex);
|
||||
break;
|
||||
case 2:
|
||||
LOGGER.WriteLine("Exited: Force"
|
||||
+ "\r\n\r\nTask End: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")); //按控制台关闭按钮关闭
|
||||
Console.CursorVisible = true;
|
||||
Console.SetCursorPosition(0, LOGGER.CursorIndex);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
@@ -226,6 +243,7 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
SetConsoleCtrlHandler(cancelHandler, true);
|
||||
try
|
||||
{
|
||||
//goto httplitsen;
|
||||
@@ -279,6 +297,8 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
int timeOut = 10; //默认10秒
|
||||
string baseUrl = "";
|
||||
string reqHeaders = "";
|
||||
string keyFile = "";
|
||||
string keyBase64 = "";
|
||||
string muxSetJson = "MUXSETS.json";
|
||||
string workDir = CURRENT_PATH + "\\Downloads";
|
||||
bool muxFastStart = false;
|
||||
@@ -314,6 +334,8 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
--retryCount Count 设定程序的重试次数(默认为15)
|
||||
--timeOut Sec 设定程序网络请求的超时时间(单位为秒,默认为10秒)
|
||||
--muxSetJson File 使用外部json文件定义混流选项
|
||||
--useKeyFile File 使用外部16字节文件定义AES-128解密KEY
|
||||
--useKeyBase64 Base64String 使用Base64字符串定义AES-128解密KEY
|
||||
--downloadRange Range 仅下载视频的一部分分片或长度
|
||||
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
||||
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
||||
@@ -324,7 +346,8 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
--enableAudioOnly 合并时仅封装音频轨道
|
||||
--disableDateInfo 关闭混流中的日期写入
|
||||
--noMerge 禁用自动合并
|
||||
--noProxy 不自动使用系统代理");
|
||||
--noProxy 不自动使用系统代理
|
||||
--disableIntegrityCheck 不检测分片数量是否完整");
|
||||
return;
|
||||
}
|
||||
if (arguments.Has("--enableDelAfterDone"))
|
||||
@@ -359,6 +382,10 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
{
|
||||
muxFastStart = true;
|
||||
}
|
||||
if (arguments.Has("--disableIntegrityCheck"))
|
||||
{
|
||||
DownloadManager.DisableIntegrityCheck = true;
|
||||
}
|
||||
if (arguments.Has("--enableAudioOnly"))
|
||||
{
|
||||
Global.VIDEO_TYPE = "IGNORE";
|
||||
@@ -374,7 +401,16 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
}
|
||||
if (arguments.Has("--saveName"))
|
||||
{
|
||||
fileName = arguments.Get("--saveName").Next;
|
||||
fileName = Global.GetValidFileName(arguments.Get("--saveName").Next);
|
||||
}
|
||||
if (arguments.Has("--useKeyFile"))
|
||||
{
|
||||
if (File.Exists(arguments.Get("--useKeyFile").Next))
|
||||
keyFile = arguments.Get("--useKeyFile").Next;
|
||||
}
|
||||
if (arguments.Has("--useKeyBase64"))
|
||||
{
|
||||
keyBase64 = arguments.Get("--useKeyBase64").Next;
|
||||
}
|
||||
if (arguments.Has("--stopSpeed"))
|
||||
{
|
||||
@@ -482,7 +518,7 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
|
||||
|
||||
//优酷DRM设备更改
|
||||
if (testurl.Contains("playlist/m3u8"))
|
||||
/*if (testurl.Contains("playlist/m3u8"))
|
||||
{
|
||||
string drm_type = Global.GetQueryString("drm_type", testurl);
|
||||
string drm_device = Global.GetQueryString("drm_device", testurl);
|
||||
@@ -494,7 +530,7 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
{
|
||||
testurl = testurl.Replace("drm_device=" + drm_device, "drm_device=11");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
string m3u8Content = string.Empty;
|
||||
bool isVOD = true;
|
||||
|
||||
@@ -509,6 +545,8 @@ namespace N_m3u8DL_CLI.NetCore
|
||||
parser.DownName = fileName;
|
||||
parser.DownDir = Path.Combine(workDir, parser.DownName);
|
||||
parser.M3u8Url = testurl;
|
||||
parser.KeyBase64 = keyBase64;
|
||||
parser.KeyFile = keyFile;
|
||||
if (baseUrl != "")
|
||||
parser.BaseUrl = baseUrl;
|
||||
parser.Headers = reqHeaders;
|
||||
|
@@ -41,7 +41,7 @@
|
||||
|
||||
# 命令行选项
|
||||
```
|
||||
N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS]
|
||||
N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
|
||||
|
||||
--workDir Directory 设定程序工作目录
|
||||
--saveName Filename 设定存储文件名(不包括后缀)
|
||||
@@ -52,6 +52,8 @@ N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS]
|
||||
--retryCount Count 设定程序的重试次数(默认为15)
|
||||
--timeOut Sec 设定程序网络请求的超时时间(单位为秒,默认为10秒)
|
||||
--muxSetJson File 使用外部json文件定义混流选项
|
||||
--useKeyFile File 使用外部16字节文件定义AES-128解密KEY
|
||||
--useKeyBase64 Base64String 使用Base64字符串定义AES-128解密KEY
|
||||
--downloadRange Range 仅下载视频的一部分分片或长度
|
||||
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
||||
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
||||
@@ -63,6 +65,7 @@ N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS]
|
||||
--disableDateInfo 关闭混流中的日期写入
|
||||
--noMerge 禁用自动合并
|
||||
--noProxy 不自动使用系统代理
|
||||
--disableIntegrityCheck 不检测分片数量是否完整
|
||||
```
|
||||
|
||||
# 用户文档
|
||||
|
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
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user