1
mirror of https://github.com/nilaoda/N_m3u8DL-CLI synced 2025-09-13 22:40:51 +02:00

Compare commits

..

36 Commits
2.8.2 ... 2.9.0

Author SHA1 Message Date
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
8 changed files with 239 additions and 448 deletions

View File

@@ -11,25 +11,12 @@ namespace N_m3u8DL_CLI
{
class DownloadManager
{
private static int calcTime = 1; //计算文件夹大小的间隔
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;
private string downDir = string.Empty;
private string downName = string.Empty;
private string muxSetJson = string.Empty;
private int threads = 1;
private int retryCount = 5;
private static int count = 0;
private static int partsCount = 0;
private int total = 0;
public static string partsPadZero = string.Empty;
string segsPadZero = string.Empty;
bool delAfterDone = false;
private bool isVTT = false;
bool externalAudio = false; //额外的音轨
string externalAudioUrl = "";
@@ -37,28 +24,56 @@ namespace N_m3u8DL_CLI
string externalSubUrl = "";
string fflogName = "_ffreport.log";
public static bool BinaryMerge = false;
private bool noMerge = false;
private bool muxFastStart = true;
private string muxFormat = "mp4";
private static bool hasSetDir = false;
public int Threads { get => threads; set => threads = value; }
public int RetryCount { get => retryCount; set => retryCount = value; }
public string Headers { get => headers; set => headers = value; }
public string DownDir { get => downDir; set => downDir = value; }
public string DownName { get => downName; set => downName = value; }
public bool DelAfterDone { get => delAfterDone; set => delAfterDone = value; }
public string MuxFormat { get => muxFormat; set => muxFormat = value; }
public bool MuxFastStart { get => muxFastStart; set => muxFastStart = value; }
public string MuxSetJson { get => muxSetJson; set => muxSetJson = value; }
public int TimeOut { get => timeOut; set => timeOut = value; }
public static double DownloadedSize { get => downloadedSize; set => downloadedSize = value; }
public static bool HasSetDir { get => hasSetDir; set => hasSetDir = value; }
public bool NoMerge { get => noMerge; set => noMerge = value; }
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 int Threads { get; set; } = 1;
public int RetryCount { get; set; } = 5;
public string Headers { get; set; } = string.Empty;
public string DownDir { get; set; } = string.Empty;
public string DownName { get; set; } = string.Empty;
public bool DelAfterDone { get; set; } = false;
public string MuxFormat { get; set; } = "mp4";
public bool MuxFastStart { get; set; } = true;
public string MuxSetJson { get; set; } = string.Empty;
public int TimeOut { get; set; } = 10000; //超时设置
public static double DownloadedSize { get; set; } = 0; //已下载大小
public static bool HasSetDir { get; set; } = false;
public bool NoMerge { get; set; } = false;
public static int CalcTime { get; set; } = 1; //计算速度的间隔
public static int Count { get; set; } = 0;
public static int PartsCount { get; set; } = 0;
public static bool DisableIntegrityCheck { get; set; } = false; //关闭完整性检查
static CancellationTokenSource cts = new CancellationTokenSource();
//计算下载速度
static System.Timers.Timer timer = new System.Timers.Timer(1000 * CalcTime); //实例化Timer类
public DownloadManager()
{
timer.AutoReset = true;
timer.Elapsed += delegate
{
Console.SetCursorPosition(0, 1);
Console.Write("Speed: " + Global.FormatFileSize((Global.BYTEDOWN) / CalcTime) + " / s".PadRight(70));
if (Global.HadReadInfo && Global.BYTEDOWN <= Global.STOP_SPEED * 1024 * CalcTime)
{
stopCount++;
Console.SetCursorPosition(0, 1);
Console.Write("Speed: " + Global.FormatFileSize((Global.BYTEDOWN) / CalcTime) + " / s [" + stopCount + "]".PadRight(70));
if (stopCount >= 12)
{
Global.ShouldStop = true;
cts.Cancel();
}
}
else
{
stopCount = 0;
Global.BYTEDOWN = 0;
}
};
}
public void DoDownload()
{
@@ -94,7 +109,6 @@ namespace N_m3u8DL_CLI
PartsCount = parts.Count;
segsPadZero = string.Empty.PadRight(oriCount.Length, '0');
partsPadZero = string.Empty.PadRight(Convert.ToString(parts.Count).Length, '0');
CancellationTokenSource cts = new CancellationTokenSource();
//是直播视频
if (isVOD == "False")
@@ -104,7 +118,6 @@ namespace N_m3u8DL_CLI
Global.ShouldStop = false; //是否该停止下载
//监控文件夹变化
if (!Directory.Exists(DownDir))
Directory.CreateDirectory(DownDir); //新建文件夹
Watcher watcher = new Watcher(DownDir);
@@ -112,41 +125,9 @@ namespace N_m3u8DL_CLI
watcher.PartsCount = PartsCount;
watcher.WatcherStrat();
//监控文件夹大小变化 via https://stackoverflow.com/questions/2869561/what-is-the-fastest-way-to-calculate-a-windows-folders-size/12665904#12665904
System.Timers.Timer timer = new System.Timers.Timer(1000 * CalcTime); //实例化Timer类
timer.AutoReset = true;
//开始计算速度
timer.Enabled = true;
//Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
//Scripting.Folder folder = fso.GetFolder(DownDir);
timer.Elapsed += delegate
{
//采用COM组件获取文件夹的大小需要引入 "Microsoft Scripting Runtime"
//double sizeInBytes = folder.Size;
Console.SetCursorPosition(0, 1);
//Console.WriteLine("Speed: " + Global.FormatFileSize((sizeInBytes - lastSizeInBytes) / calcTime) + " / s ");
Console.Write("Speed: " + Global.FormatFileSize((Global.BYTEDOWN) / CalcTime) + " / s".PadRight(70));
if (Global.HadReadInfo && Global.BYTEDOWN <= Global.STOP_SPEED * 1024 * CalcTime)
{
stopCount++;
Console.SetCursorPosition(0, 1);
Console.Write("Speed: " + Global.FormatFileSize((Global.BYTEDOWN) / CalcTime) + " / s [" + stopCount + "]".PadRight(70));
if (stopCount >= 12)
{
Global.ShouldStop = true;
cts.Cancel();
GC.Collect();
return;
}
}
else
{
stopCount = 0;
Global.BYTEDOWN = 0;
}
};
cts = new CancellationTokenSource();
//开始调用下载
LOGGER.WriteLine(strings.startDownloading);
@@ -200,16 +181,10 @@ namespace N_m3u8DL_CLI
sd.Key = firstSeg["key"].Value<string>();
sd.Iv = firstSeg["iv"].Value<string>();
}
try
{
if (firstSeg["expectByte"] != null)
sd.ExpectByte = firstSeg["expectByte"].Value<long>();
}
catch (Exception) { }
try
{
if (firstSeg["startByte"] != null)
sd.StartByte = firstSeg["startByte"].Value<long>();
}
catch (Exception) { }
sd.Headers = Headers;
sd.SavePath = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
if (File.Exists(sd.SavePath))
@@ -290,16 +265,10 @@ namespace N_m3u8DL_CLI
sd.Key = info["key"].Value<string>();
sd.Iv = info["iv"].Value<string>();
}
try
{
if (firstSeg["expectByte"] != null)
sd.ExpectByte = info["expectByte"].Value<long>();
}
catch (Exception) { }
try
{
if (firstSeg["startByte"] != null)
sd.StartByte = info["startByte"].Value<long>();
}
catch (Exception) { }
sd.Headers = Headers;
sd.SavePath = DownDir + "\\Part_" + info["part"].Value<int>().ToString(partsPadZero) + "\\" + info["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
if (File.Exists(sd.SavePath))
@@ -327,12 +296,8 @@ namespace N_m3u8DL_CLI
watcher.WatcherStop();
//监控文件夹大小变化的收尾工作
//停止速度监测
timer.Enabled = false;
timer.Close();
// cleanup COM
//System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
//System.Runtime.InteropServices.Marshal.ReleaseComObject(fso);
//检测是否下完
IsComplete(Convert.ToInt32(segCount));
@@ -363,14 +328,13 @@ namespace N_m3u8DL_CLI
Count++;
LOGGER.WriteLine(strings.retryCount + Count + " / " + RetryCount);
LOGGER.PrintLine(strings.retryCount + Count + " / " + RetryCount, LOGGER.Warning);
Thread.Sleep(3000);
GC.Collect(); //垃圾回收
Thread.Sleep(6000);
DoDownload();
}
}
else //开始合并
{
LOGGER.PrintLine(strings.downloadComplete + (DisableIntegrityCheck ? "("+strings.disableIntegrityCheck+")" : ""));
LOGGER.PrintLine(strings.downloadComplete + (DisableIntegrityCheck ? "(" + strings.disableIntegrityCheck + ")" : ""));
Console.WriteLine();
if (NoMerge == false)
{
@@ -539,7 +503,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(strings.startMerging);
for (int i = 0; i < PartsCount; i++)
@@ -640,7 +604,7 @@ namespace N_m3u8DL_CLI
parser.DownDir = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
LOGGER.WriteLine(strings.startParsing + externalAudioUrl);
LOGGER.WriteLine(strings.downloadingExternalAudioTrack);
DownName = DownName + "(Audio)";
DownName = parser.DownName;
fflogName = "_ffreport(Audio).log";
DownDir = parser.DownDir;
parser.Parse(); //开始解析

View File

@@ -30,8 +30,9 @@ namespace N_m3u8DL_CLI
/*===============================================================================*/
static string nowVer = "2.8.2";
static string nowDate = "20201122";
static Version ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
static string nowVer = $"{ver.Major}.{ver.Minor}.{ver.Build}";
static string nowDate = "20201206";
public static void WriteInit()
{
Console.Clear();
@@ -109,7 +110,7 @@ namespace N_m3u8DL_CLI
HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
webRequest.Method = "GET";
if (NoProxy) webRequest.Proxy = null;
webRequest.UserAgent = "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36";
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36";
webRequest.Accept = "*/*";
webRequest.Headers.Add("Accept-Encoding", "gzip, deflate, br");
webRequest.Timeout = TimeOut; //设置超时
@@ -119,7 +120,7 @@ namespace N_m3u8DL_CLI
{
webRequest.UserAgent = "";
if (!url.Contains("/internettv/"))
webRequest.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
webRequest.Referer = "https://www.mgtv.com";
webRequest.Headers.Add("Cookie", "MQGUID");
}
//添加headers
@@ -157,7 +158,7 @@ namespace N_m3u8DL_CLI
}
//文件过大则认为不是m3u8
if (webResponse.ContentLength != -1 && webRequest.ContentLength > 50 * 1024 * 1024) return "";
if (webResponse.ContentLength != -1 && webResponse.ContentLength > 50 * 1024 * 1024) return "";
if (webResponse.ContentEncoding != null
&& webResponse.ContentEncoding.ToLower() == "gzip") //如果使用了GZip则先解压
@@ -426,7 +427,7 @@ namespace N_m3u8DL_CLI
if (NoProxy) req.Proxy = null;
req.Headers.Add("Accept-Encoding", "gzip, deflate");
req.Accept = "*/*";
req.UserAgent = "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36";
req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36";
//添加headers
if (headers != "")
{
@@ -535,11 +536,11 @@ namespace N_m3u8DL_CLI
{
request.UserAgent = "";
if (!url.Contains("/internettv/"))
request.Referer = "https://player.mgtv.com/mgtv_v6_player/PlayerCore.swf";
request.Referer = "https://www.mgtv.com";
request.Headers.Add("Cookie", "MQGUID");
}
else
request.UserAgent = "Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36";
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36";
//下载部分字节
if (expectByte != -1)
request.AddRange("bytes", startByte, startByte + expectByte - 1);

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
<?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="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +13,8 @@
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
@@ -38,6 +41,9 @@
<ApplicationIcon>logo_3Iv_icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<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.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">
@@ -130,4 +136,12 @@
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\Fody.6.0.0\build\Fody.targets" Condition="Exists('..\packages\Fody.6.0.0\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<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>
</Project>

View File

@@ -118,7 +118,7 @@ namespace N_m3u8DL_CLI
m3u8Content = DecodeImooc.DecodeM3u8(m3u8Content);
}
if (m3u8Content.Trim().StartsWith("<?xml version") && m3u8Content.Contains("<MPD"))
if (m3u8Content.Contains("</MPD>") && m3u8Content.Contains("<MPD"))
{
var mpdSavePath = Path.Combine(DownDir, "dash.mpd");
//输出mpd文件
@@ -660,7 +660,7 @@ namespace N_m3u8DL_CLI
string keyUrl = key[1];
if (isQiQiuYun)
{
string encKey = Encoding.Default.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
/*string encKey = Encoding.Default.GetString(Global.HttpDownloadFileToBytes(keyUrl, Headers));
var indexs = "0-1-2-3-4-5-6-7-8-10-11-12-14-15-16-18".Split('-');
if (encKey.Length == 20)
{
@@ -740,7 +740,9 @@ namespace N_m3u8DL_CLI
{
decKey += encKey[Convert.ToInt32(_i)];
}
key[1] = Convert.ToBase64String(Encoding.Default.GetBytes(decKey));
key[1] = Convert.ToBase64String(Encoding.Default.GetBytes(decKey));*/
key[1] = Convert.ToBase64String(Global.HttpDownloadFileToBytes(keyUrl, "User-Agent:Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36"));
} //气球云
else if (key[1].Contains("imooc.com/"))
{
@@ -864,9 +866,7 @@ namespace N_m3u8DL_CLI
/// <returns></returns>
public static string GetBaseUrl(string m3u8url, string headers)
{
if (!isQiQiuYun && Global.Get302(m3u8url, headers) != m3u8url)
m3u8url = Global.Get302(m3u8url, headers);
string url = Global.Get302(m3u8url);
string url = Global.Get302(m3u8url, headers);
if (url.Contains("?"))
url = url.Remove(url.LastIndexOf('?'));
url = url.Substring(0, url.LastIndexOf('/') + 1);

File diff suppressed because it is too large Load Diff

View File

@@ -286,4 +286,19 @@
- 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请求气球云密钥服务器

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Fody" version="6.0.0" targetFramework="net46" developmentDependency="true" />
<package id="Costura.Fody" version="4.1.0" targetFramework="net46" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
<package id="NiL.JS" version="2.5.1428" targetFramework="net46" />
</packages>