You've already forked N_m3u8DL-CLI
mirror of
https://github.com/nilaoda/N_m3u8DL-CLI
synced 2025-11-06 10:42:32 +01:00
Compare commits
93 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5267be1699 | ||
|
|
20bfda39e7 | ||
|
|
ba4c0eeda7 | ||
|
|
5d72e24002 | ||
|
|
a87c051d23 | ||
|
|
44e1b68d6b | ||
|
|
e65dfa52cd | ||
|
|
965c173899 | ||
|
|
880af02cc2 | ||
|
|
2742de43c4 | ||
|
|
9d8cb57390 | ||
|
|
9e2a192dab | ||
|
|
33cf9e2256 | ||
|
|
2959cbbb5c | ||
|
|
c2eb8a6adc | ||
|
|
e1b591b81c | ||
|
|
334b1939b5 | ||
|
|
7e916b65fd | ||
|
|
4ead563fa2 | ||
|
|
1b387a06e5 | ||
|
|
6e7b4ac7ea | ||
|
|
e98c5205d1 | ||
|
|
d7890dd124 | ||
|
|
82f2111522 | ||
|
|
4c3207586f | ||
|
|
69b411e37c | ||
|
|
1e8525041f | ||
|
|
65ae72d4a4 | ||
|
|
4a4bfae5ab | ||
|
|
d586dddfcd | ||
|
|
fca6b3ff6c | ||
|
|
5d75626a36 | ||
|
|
a94271c244 | ||
|
|
c51118dce7 | ||
|
|
81b2e87bf7 | ||
|
|
71a9878aaa | ||
|
|
769fe4e926 | ||
|
|
1f57ba7c09 | ||
|
|
71282bda30 | ||
|
|
41ee8aebdf | ||
|
|
a4537bc093 | ||
|
|
b8a60b3917 | ||
|
|
8091dd290f | ||
|
|
d48e84e611 | ||
|
|
9f5423a437 | ||
|
|
ce7e38770a | ||
|
|
8fdb2e918e | ||
|
|
d4b7d240c1 | ||
|
|
484d2941ed | ||
|
|
a0f2b66575 | ||
|
|
65cc0681e2 | ||
|
|
7d980ec9a2 | ||
|
|
ec5892c05a | ||
|
|
9aed50fbf9 | ||
|
|
d657b455cd | ||
|
|
cda6575605 | ||
|
|
0d6377d41b | ||
|
|
9c76bdcbce | ||
|
|
83915ff606 | ||
|
|
9cd4746f33 | ||
|
|
33a5b917ac | ||
|
|
f69978bd82 | ||
|
|
d9fd526886 | ||
|
|
1cc8ecfaaf | ||
|
|
2bc2dde2ad | ||
|
|
c3ddcf9e0e | ||
|
|
ba5d20dd02 | ||
|
|
16f705fe66 | ||
|
|
d141cabc4a | ||
|
|
adcf884a93 | ||
|
|
9d903a025f | ||
|
|
0bd23ab641 | ||
|
|
a38f27ccd7 | ||
|
|
3acec5efd3 | ||
|
|
90874e4bfe | ||
|
|
b94768e3e8 | ||
|
|
311f3b882e | ||
|
|
4b4f537984 | ||
|
|
8032d50b42 | ||
|
|
f615764e55 | ||
|
|
ccaa200ef8 | ||
|
|
6058d878eb | ||
|
|
c712c6dee0 | ||
|
|
bb24bb998f | ||
|
|
e9d951efa5 | ||
|
|
6f88a805ef | ||
|
|
6aa6d63a8d | ||
|
|
147246caba | ||
|
|
35c1ee4777 | ||
|
|
8b32081b85 | ||
|
|
c00de328d1 | ||
|
|
d5193c1645 | ||
|
|
c06fbf5820 |
4
.github/workflows/build_latest.yml
vendored
4
.github/workflows/build_latest.yml
vendored
@@ -13,9 +13,13 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup MSBuild Path
|
- name: Setup MSBuild Path
|
||||||
uses: warrenbuckley/Setup-MSBuild@v1
|
uses: warrenbuckley/Setup-MSBuild@v1
|
||||||
|
env:
|
||||||
|
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||||
|
|
||||||
- name: Setup NuGet
|
- name: Setup NuGet
|
||||||
uses: NuGet/setup-nuget@v1.0.2
|
uses: NuGet/setup-nuget@v1.0.2
|
||||||
|
env:
|
||||||
|
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||||
|
|
||||||
- name: Restore NuGet Packages
|
- name: Restore NuGet Packages
|
||||||
run: nuget restore N_m3u8DL-CLI.sln
|
run: nuget restore N_m3u8DL-CLI.sln
|
||||||
|
|||||||
53
N_m3u8DL-CLI/DecodeHuke88Key.cs
Normal file
53
N_m3u8DL-CLI/DecodeHuke88Key.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace N_m3u8DL_CLI
|
namespace N_m3u8DL_CLI
|
||||||
{
|
{
|
||||||
class Decrypter
|
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);
|
FileStream fs = new FileStream(filePath, FileMode.Open);
|
||||||
//获取文件大小
|
//获取文件大小
|
||||||
@@ -25,14 +21,14 @@ namespace N_m3u8DL_CLI
|
|||||||
dcpt.Key = keyByte;
|
dcpt.Key = keyByte;
|
||||||
dcpt.IV = ivByte;
|
dcpt.IV = ivByte;
|
||||||
dcpt.Mode = mode;
|
dcpt.Mode = mode;
|
||||||
dcpt.Padding = PaddingMode.PKCS7;
|
dcpt.Padding = padding;
|
||||||
|
|
||||||
ICryptoTransform cTransform = dcpt.CreateDecryptor();
|
ICryptoTransform cTransform = dcpt.CreateDecryptor();
|
||||||
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
|
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
|
||||||
return resultArray;
|
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;
|
byte[] inBuff = encryptedBuff;
|
||||||
|
|
||||||
@@ -42,7 +38,7 @@ namespace N_m3u8DL_CLI
|
|||||||
dcpt.Key = keyByte;
|
dcpt.Key = keyByte;
|
||||||
dcpt.IV = ivByte;
|
dcpt.IV = ivByte;
|
||||||
dcpt.Mode = mode;
|
dcpt.Mode = mode;
|
||||||
dcpt.Padding = PaddingMode.PKCS7;
|
dcpt.Padding = padding;
|
||||||
|
|
||||||
ICryptoTransform cTransform = dcpt.CreateDecryptor();
|
ICryptoTransform cTransform = dcpt.CreateDecryptor();
|
||||||
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
|
Byte[] resultArray = cTransform.TransformFinalBlock(inBuff, 0, inBuff.Length);
|
||||||
|
|||||||
@@ -11,25 +11,12 @@ namespace N_m3u8DL_CLI
|
|||||||
{
|
{
|
||||||
class DownloadManager
|
class DownloadManager
|
||||||
{
|
{
|
||||||
private static int calcTime = 1; //计算文件夹大小的间隔
|
|
||||||
private int stopCount = 0; //速度为零的停止
|
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 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;
|
private int total = 0;
|
||||||
public static string partsPadZero = string.Empty;
|
public static string partsPadZero = string.Empty;
|
||||||
string segsPadZero = string.Empty;
|
string segsPadZero = string.Empty;
|
||||||
bool delAfterDone = false;
|
|
||||||
private bool isVTT = false;
|
private bool isVTT = false;
|
||||||
bool externalAudio = false; //额外的音轨
|
bool externalAudio = false; //额外的音轨
|
||||||
string externalAudioUrl = "";
|
string externalAudioUrl = "";
|
||||||
@@ -37,28 +24,56 @@ namespace N_m3u8DL_CLI
|
|||||||
string externalSubUrl = "";
|
string externalSubUrl = "";
|
||||||
string fflogName = "_ffreport.log";
|
string fflogName = "_ffreport.log";
|
||||||
public static bool BinaryMerge = false;
|
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 Threads { get; set; } = 1;
|
||||||
public int RetryCount { get => retryCount; set => retryCount = value; }
|
public int RetryCount { get; set; } = 5;
|
||||||
public string Headers { get => headers; set => headers = value; }
|
public string Headers { get; set; } = string.Empty;
|
||||||
public string DownDir { get => downDir; set => downDir = value; }
|
public string DownDir { get; set; } = string.Empty;
|
||||||
public string DownName { get => downName; set => downName = value; }
|
public string DownName { get; set; } = string.Empty;
|
||||||
public bool DelAfterDone { get => delAfterDone; set => delAfterDone = value; }
|
public bool DelAfterDone { get; set; } = false;
|
||||||
public string MuxFormat { get => muxFormat; set => muxFormat = value; }
|
public string MuxFormat { get; set; } = "mp4";
|
||||||
public bool MuxFastStart { get => muxFastStart; set => muxFastStart = value; }
|
public bool MuxFastStart { get; set; } = true;
|
||||||
public string MuxSetJson { get => muxSetJson; set => muxSetJson = value; }
|
public string MuxSetJson { get; set; } = string.Empty;
|
||||||
public int TimeOut { get => timeOut; set => timeOut = value; }
|
public int TimeOut { get; set; } = 10000; //超时设置
|
||||||
public static double DownloadedSize { get => downloadedSize; set => downloadedSize = value; }
|
public static double DownloadedSize { get; set; } = 0; //已下载大小
|
||||||
public static bool HasSetDir { get => hasSetDir; set => hasSetDir = value; }
|
public static bool HasSetDir { get; set; } = false;
|
||||||
public bool NoMerge { get => noMerge; set => noMerge = value; }
|
public bool NoMerge { get; set; } = false;
|
||||||
public static int CalcTime { get => calcTime; set => calcTime = value; }
|
public static int CalcTime { get; set; } = 1; //计算速度的间隔
|
||||||
public static int Count { get => count; set => count = value; }
|
public static int Count { get; set; } = 0;
|
||||||
public static int PartsCount { get => partsCount; set => partsCount = value; }
|
public static int PartsCount { get; set; } = 0;
|
||||||
public static bool DisableIntegrityCheck { get => disableIntegrityCheck; set => disableIntegrityCheck = value; }
|
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()
|
public void DoDownload()
|
||||||
{
|
{
|
||||||
@@ -94,7 +109,6 @@ namespace N_m3u8DL_CLI
|
|||||||
PartsCount = parts.Count;
|
PartsCount = parts.Count;
|
||||||
segsPadZero = string.Empty.PadRight(oriCount.Length, '0');
|
segsPadZero = string.Empty.PadRight(oriCount.Length, '0');
|
||||||
partsPadZero = string.Empty.PadRight(Convert.ToString(parts.Count).Length, '0');
|
partsPadZero = string.Empty.PadRight(Convert.ToString(parts.Count).Length, '0');
|
||||||
CancellationTokenSource cts = new CancellationTokenSource();
|
|
||||||
|
|
||||||
//是直播视频
|
//是直播视频
|
||||||
if (isVOD == "False")
|
if (isVOD == "False")
|
||||||
@@ -104,7 +118,6 @@ namespace N_m3u8DL_CLI
|
|||||||
|
|
||||||
Global.ShouldStop = false; //是否该停止下载
|
Global.ShouldStop = false; //是否该停止下载
|
||||||
|
|
||||||
//监控文件夹变化
|
|
||||||
if (!Directory.Exists(DownDir))
|
if (!Directory.Exists(DownDir))
|
||||||
Directory.CreateDirectory(DownDir); //新建文件夹
|
Directory.CreateDirectory(DownDir); //新建文件夹
|
||||||
Watcher watcher = new Watcher(DownDir);
|
Watcher watcher = new Watcher(DownDir);
|
||||||
@@ -112,41 +125,9 @@ namespace N_m3u8DL_CLI
|
|||||||
watcher.PartsCount = PartsCount;
|
watcher.PartsCount = PartsCount;
|
||||||
watcher.WatcherStrat();
|
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;
|
timer.Enabled = true;
|
||||||
//Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
|
cts = new CancellationTokenSource();
|
||||||
//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;
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//开始调用下载
|
//开始调用下载
|
||||||
LOGGER.WriteLine(strings.startDownloading);
|
LOGGER.WriteLine(strings.startDownloading);
|
||||||
@@ -200,16 +181,10 @@ namespace N_m3u8DL_CLI
|
|||||||
sd.Key = firstSeg["key"].Value<string>();
|
sd.Key = firstSeg["key"].Value<string>();
|
||||||
sd.Iv = firstSeg["iv"].Value<string>();
|
sd.Iv = firstSeg["iv"].Value<string>();
|
||||||
}
|
}
|
||||||
try
|
if (firstSeg["expectByte"] != null)
|
||||||
{
|
|
||||||
sd.ExpectByte = firstSeg["expectByte"].Value<long>();
|
sd.ExpectByte = firstSeg["expectByte"].Value<long>();
|
||||||
}
|
if (firstSeg["startByte"] != null)
|
||||||
catch (Exception) { }
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sd.StartByte = firstSeg["startByte"].Value<long>();
|
sd.StartByte = firstSeg["startByte"].Value<long>();
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
sd.Headers = Headers;
|
sd.Headers = Headers;
|
||||||
sd.SavePath = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
|
sd.SavePath = DownDir + "\\Part_" + 0.ToString(partsPadZero) + "\\" + firstSeg["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
|
||||||
if (File.Exists(sd.SavePath))
|
if (File.Exists(sd.SavePath))
|
||||||
@@ -290,16 +265,10 @@ namespace N_m3u8DL_CLI
|
|||||||
sd.Key = info["key"].Value<string>();
|
sd.Key = info["key"].Value<string>();
|
||||||
sd.Iv = info["iv"].Value<string>();
|
sd.Iv = info["iv"].Value<string>();
|
||||||
}
|
}
|
||||||
try
|
if (firstSeg["expectByte"] != null)
|
||||||
{
|
|
||||||
sd.ExpectByte = info["expectByte"].Value<long>();
|
sd.ExpectByte = info["expectByte"].Value<long>();
|
||||||
}
|
if (firstSeg["startByte"] != null)
|
||||||
catch (Exception) { }
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sd.StartByte = info["startByte"].Value<long>();
|
sd.StartByte = info["startByte"].Value<long>();
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
sd.Headers = Headers;
|
sd.Headers = Headers;
|
||||||
sd.SavePath = DownDir + "\\Part_" + info["part"].Value<int>().ToString(partsPadZero) + "\\" + info["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
|
sd.SavePath = DownDir + "\\Part_" + info["part"].Value<int>().ToString(partsPadZero) + "\\" + info["index"].Value<int>().ToString(segsPadZero) + ".tsdownloading";
|
||||||
if (File.Exists(sd.SavePath))
|
if (File.Exists(sd.SavePath))
|
||||||
@@ -327,12 +296,8 @@ namespace N_m3u8DL_CLI
|
|||||||
|
|
||||||
watcher.WatcherStop();
|
watcher.WatcherStop();
|
||||||
|
|
||||||
//监控文件夹大小变化的收尾工作
|
//停止速度监测
|
||||||
timer.Enabled = false;
|
timer.Enabled = false;
|
||||||
timer.Close();
|
|
||||||
// cleanup COM
|
|
||||||
//System.Runtime.InteropServices.Marshal.ReleaseComObject(folder);
|
|
||||||
//System.Runtime.InteropServices.Marshal.ReleaseComObject(fso);
|
|
||||||
|
|
||||||
//检测是否下完
|
//检测是否下完
|
||||||
IsComplete(Convert.ToInt32(segCount));
|
IsComplete(Convert.ToInt32(segCount));
|
||||||
@@ -363,8 +328,7 @@ namespace N_m3u8DL_CLI
|
|||||||
Count++;
|
Count++;
|
||||||
LOGGER.WriteLine(strings.retryCount + Count + " / " + RetryCount);
|
LOGGER.WriteLine(strings.retryCount + Count + " / " + RetryCount);
|
||||||
LOGGER.PrintLine(strings.retryCount + Count + " / " + RetryCount, LOGGER.Warning);
|
LOGGER.PrintLine(strings.retryCount + Count + " / " + RetryCount, LOGGER.Warning);
|
||||||
Thread.Sleep(3000);
|
Thread.Sleep(6000);
|
||||||
GC.Collect(); //垃圾回收
|
|
||||||
DoDownload();
|
DoDownload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -404,6 +368,8 @@ namespace N_m3u8DL_CLI
|
|||||||
//有MAP文件,一般为mp4,采取默认动作
|
//有MAP文件,一般为mp4,采取默认动作
|
||||||
if(File.Exists(DownDir + "\\Part_0\\!MAP.ts"))
|
if(File.Exists(DownDir + "\\Part_0\\!MAP.ts"))
|
||||||
MuxFormat = "mp4";
|
MuxFormat = "mp4";
|
||||||
|
if (isVTT)
|
||||||
|
MuxFormat = "vtt";
|
||||||
|
|
||||||
if (Global.AUDIO_TYPE != "")
|
if (Global.AUDIO_TYPE != "")
|
||||||
MuxFormat = Global.AUDIO_TYPE;
|
MuxFormat = Global.AUDIO_TYPE;
|
||||||
@@ -564,6 +530,8 @@ namespace N_m3u8DL_CLI
|
|||||||
//有MAP文件,一般为mp4,采取默认动作
|
//有MAP文件,一般为mp4,采取默认动作
|
||||||
if (File.Exists(DownDir + "\\!MAP.ts"))
|
if (File.Exists(DownDir + "\\!MAP.ts"))
|
||||||
MuxFormat = "mp4";
|
MuxFormat = "mp4";
|
||||||
|
if (isVTT)
|
||||||
|
MuxFormat = "vtt";
|
||||||
Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir, ".ts"), FFmpeg.OutPutPath + $".{MuxFormat}");
|
Global.CombineMultipleFilesIntoSingleFile(Global.GetFiles(DownDir, ".ts"), FFmpeg.OutPutPath + $".{MuxFormat}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -640,7 +608,7 @@ namespace N_m3u8DL_CLI
|
|||||||
parser.DownDir = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
|
parser.DownDir = Path.Combine(Path.GetDirectoryName(DownDir), parser.DownName);
|
||||||
LOGGER.WriteLine(strings.startParsing + externalAudioUrl);
|
LOGGER.WriteLine(strings.startParsing + externalAudioUrl);
|
||||||
LOGGER.WriteLine(strings.downloadingExternalAudioTrack);
|
LOGGER.WriteLine(strings.downloadingExternalAudioTrack);
|
||||||
DownName = DownName + "(Audio)";
|
DownName = parser.DownName;
|
||||||
fflogName = "_ffreport(Audio).log";
|
fflogName = "_ffreport(Audio).log";
|
||||||
DownDir = parser.DownDir;
|
DownDir = parser.DownDir;
|
||||||
parser.Parse(); //开始解析
|
parser.Parse(); //开始解析
|
||||||
|
|||||||
@@ -11,20 +11,19 @@ namespace N_m3u8DL_CLI
|
|||||||
class FFmpeg
|
class FFmpeg
|
||||||
{
|
{
|
||||||
public static string FFMPEG_PATH = "ffmpeg";
|
public static string FFMPEG_PATH = "ffmpeg";
|
||||||
|
public static string REC_TIME = ""; //录制日期
|
||||||
|
|
||||||
private static string outPutPath = string.Empty;
|
public static string OutPutPath { get; set; } = string.Empty;
|
||||||
private static string reportFile = string.Empty;
|
public static string ReportFile { get; set; } = string.Empty;
|
||||||
private static bool useAACFilter = false; //是否启用滤镜
|
public static bool UseAACFilter { get; set; } = false; //是否启用滤镜
|
||||||
private static bool writeDate = true; //是否写入录制日期
|
public static bool WriteDate { get; set; } = true; //是否写入录制日期
|
||||||
public static string OutPutPath { get => outPutPath; set => outPutPath = value; }
|
|
||||||
public static string ReportFile { get => reportFile; set => reportFile = value; }
|
|
||||||
public static bool UseAACFilter { get => useAACFilter; set => useAACFilter = value; }
|
|
||||||
public static bool WriteDate { get => writeDate; set => writeDate = value; }
|
|
||||||
|
|
||||||
public static void Merge(string[] files, string muxFormat, bool fastStart,
|
public static void Merge(string[] files, string muxFormat, bool fastStart,
|
||||||
string poster = "", string audioName = "", string title = "",
|
string poster = "", string audioName = "", string title = "",
|
||||||
string copyright = "", string comment = "", string encodingTool = "")
|
string copyright = "", string comment = "", string encodingTool = "")
|
||||||
{
|
{
|
||||||
|
string dateString = string.IsNullOrEmpty(REC_TIME) ? DateTime.Now.ToString("o") : REC_TIME;
|
||||||
|
|
||||||
//同名文件已存在的共存策略
|
//同名文件已存在的共存策略
|
||||||
if (File.Exists($"{OutPutPath}.{muxFormat.ToLower()}"))
|
if (File.Exists($"{OutPutPath}.{muxFormat.ToLower()}"))
|
||||||
{
|
{
|
||||||
@@ -52,7 +51,7 @@ namespace N_m3u8DL_CLI
|
|||||||
command += " " + (string.IsNullOrEmpty(ddpAudio) ? "" : "-i \"" + ddpAudio + "\"");
|
command += " " + (string.IsNullOrEmpty(ddpAudio) ? "" : "-i \"" + ddpAudio + "\"");
|
||||||
command +=
|
command +=
|
||||||
$" -map 0:v? {(string.IsNullOrEmpty(ddpAudio) ? "-map 0:a?" : $"-map {(string.IsNullOrEmpty(poster) ? "1" : "2")}:a -map 0:a?")} -map 0:s? " + (string.IsNullOrEmpty(poster) ? "" : addPoster)
|
$" -map 0:v? {(string.IsNullOrEmpty(ddpAudio) ? "-map 0:a?" : $"-map {(string.IsNullOrEmpty(poster) ? "1" : "2")}:a -map 0:a?")} -map 0:s? " + (string.IsNullOrEmpty(poster) ? "" : addPoster)
|
||||||
+ (writeDate ? " -metadata date=\"" + DateTime.Now.ToString("o") + "\"" : "") +
|
+ (WriteDate ? " -metadata date=\"" + dateString + "\"" : "") +
|
||||||
" -metadata encoding_tool=\"" + encodingTool + "\" -metadata title=\"" + title +
|
" -metadata encoding_tool=\"" + encodingTool + "\" -metadata title=\"" + title +
|
||||||
"\" -metadata copyright=\"" + copyright + "\" -metadata comment=\"" + comment +
|
"\" -metadata copyright=\"" + copyright + "\" -metadata comment=\"" + comment +
|
||||||
$"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler_name=\"" + audioName + $"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler=\"" + audioName + "\" ";
|
$"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler_name=\"" + audioName + $"\" -metadata:s:a:{(string.IsNullOrEmpty(ddpAudio) ? "0" : "1")} handler=\"" + audioName + "\" ";
|
||||||
|
|||||||
@@ -24,14 +24,17 @@ namespace N_m3u8DL_CLI
|
|||||||
public static string AUDIO_TYPE = "";
|
public static string AUDIO_TYPE = "";
|
||||||
public static bool HadReadInfo = false;
|
public static bool HadReadInfo = false;
|
||||||
private static bool noProxy = false;
|
private static bool noProxy = false;
|
||||||
|
private static string useProxyAddress = "";
|
||||||
|
|
||||||
public static bool ShouldStop { get => shouldStop; set => shouldStop = value; }
|
public static bool ShouldStop { get => shouldStop; set => shouldStop = value; }
|
||||||
public static bool NoProxy { get => noProxy; set => noProxy = value; }
|
public static bool NoProxy { get => noProxy; set => noProxy = value; }
|
||||||
|
public static string UseProxyAddress { get => useProxyAddress; set => useProxyAddress = value; }
|
||||||
|
|
||||||
|
|
||||||
/*===============================================================================*/
|
/*===============================================================================*/
|
||||||
static string nowVer = "2.7.5";
|
static Version ver = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
static string nowDate = "20201014";
|
static string nowVer = $"{ver.Major}.{ver.Minor}.{ver.Build}";
|
||||||
|
static string nowDate = "20210201";
|
||||||
public static void WriteInit()
|
public static void WriteInit()
|
||||||
{
|
{
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
@@ -105,19 +108,30 @@ namespace N_m3u8DL_CLI
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
reProcess:
|
||||||
HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
|
HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
|
||||||
webRequest.Method = "GET";
|
webRequest.Method = "GET";
|
||||||
if (NoProxy) webRequest.Proxy = null;
|
if (NoProxy)
|
||||||
webRequest.UserAgent = "Mozilla/4.0";
|
{
|
||||||
webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
|
webRequest.Proxy = null;
|
||||||
|
}
|
||||||
|
else if (UseProxyAddress != "")
|
||||||
|
{
|
||||||
|
WebProxy proxy = new WebProxy(UseProxyAddress);
|
||||||
|
//proxy.Credentials = new NetworkCredential(username, password);
|
||||||
|
webRequest.Proxy = proxy;
|
||||||
|
}
|
||||||
|
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; //设置超时
|
webRequest.Timeout = TimeOut; //设置超时
|
||||||
webRequest.KeepAlive = false;
|
webRequest.KeepAlive = false;
|
||||||
webRequest.AllowAutoRedirect = true; //自动跳转
|
webRequest.AllowAutoRedirect = false; //手动处理重定向,否则会丢失Referer
|
||||||
if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
||||||
{
|
{
|
||||||
webRequest.UserAgent = "";
|
webRequest.UserAgent = "";
|
||||||
if (!url.Contains("/internettv/"))
|
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");
|
webRequest.Headers.Add("Cookie", "MQGUID");
|
||||||
}
|
}
|
||||||
//添加headers
|
//添加headers
|
||||||
@@ -145,6 +159,18 @@ namespace N_m3u8DL_CLI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
|
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
|
||||||
|
|
||||||
|
//302
|
||||||
|
if (webResponse.Headers.Get("Location") != null)
|
||||||
|
{
|
||||||
|
url = webResponse.Headers.Get("Location");
|
||||||
|
webResponse.Close();
|
||||||
|
goto reProcess;
|
||||||
|
}
|
||||||
|
|
||||||
|
//文件过大则认为不是m3u8
|
||||||
|
if (webResponse.ContentLength != -1 && webResponse.ContentLength > 50 * 1024 * 1024) return "";
|
||||||
|
|
||||||
if (webResponse.ContentEncoding != null
|
if (webResponse.ContentEncoding != null
|
||||||
&& webResponse.ContentEncoding.ToLower() == "gzip") //如果使用了GZip则先解压
|
&& webResponse.ContentEncoding.ToLower() == "gzip") //如果使用了GZip则先解压
|
||||||
{
|
{
|
||||||
@@ -355,7 +381,16 @@ namespace N_m3u8DL_CLI
|
|||||||
string redirectUrl;
|
string redirectUrl;
|
||||||
WebRequest myRequest = WebRequest.Create(url);
|
WebRequest myRequest = WebRequest.Create(url);
|
||||||
myRequest.Timeout = timeout;
|
myRequest.Timeout = timeout;
|
||||||
if (NoProxy) myRequest.Proxy = null;
|
if (NoProxy)
|
||||||
|
{
|
||||||
|
myRequest.Proxy = null;
|
||||||
|
}
|
||||||
|
else if (UseProxyAddress != "")
|
||||||
|
{
|
||||||
|
WebProxy proxy = new WebProxy(UseProxyAddress);
|
||||||
|
//proxy.Credentials = new NetworkCredential(username, password);
|
||||||
|
myRequest.Proxy = proxy;
|
||||||
|
}
|
||||||
//添加headers
|
//添加headers
|
||||||
if (headers != "")
|
if (headers != "")
|
||||||
{
|
{
|
||||||
@@ -402,14 +437,26 @@ namespace N_m3u8DL_CLI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reProcess:
|
||||||
byte[] arraryByte;
|
byte[] arraryByte;
|
||||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
||||||
req.Method = "GET";
|
req.Method = "GET";
|
||||||
req.Timeout = timeOut;
|
req.Timeout = timeOut;
|
||||||
req.ReadWriteTimeout = timeOut; //重要
|
req.ReadWriteTimeout = timeOut; //重要
|
||||||
if (NoProxy) req.Proxy = null;
|
req.AllowAutoRedirect = false; //手动处理重定向,否则会丢失Referer
|
||||||
|
if (NoProxy)
|
||||||
|
{
|
||||||
|
req.Proxy = null;
|
||||||
|
}
|
||||||
|
else if (UseProxyAddress != "")
|
||||||
|
{
|
||||||
|
WebProxy proxy = new WebProxy(UseProxyAddress);
|
||||||
|
//proxy.Credentials = new NetworkCredential(username, password);
|
||||||
|
req.Proxy = proxy;
|
||||||
|
}
|
||||||
req.Headers.Add("Accept-Encoding", "gzip, deflate");
|
req.Headers.Add("Accept-Encoding", "gzip, deflate");
|
||||||
req.Accept = "*/*";
|
req.Accept = "*/*";
|
||||||
|
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
|
//添加headers
|
||||||
if (headers != "")
|
if (headers != "")
|
||||||
{
|
{
|
||||||
@@ -437,6 +484,13 @@ namespace N_m3u8DL_CLI
|
|||||||
|
|
||||||
using (HttpWebResponse wr = (HttpWebResponse)req.GetResponse())
|
using (HttpWebResponse wr = (HttpWebResponse)req.GetResponse())
|
||||||
{
|
{
|
||||||
|
//302
|
||||||
|
if (wr.Headers.Get("Location") != null)
|
||||||
|
{
|
||||||
|
url = wr.Headers.Get("Location");
|
||||||
|
wr.Close();
|
||||||
|
goto reProcess;
|
||||||
|
}
|
||||||
if (wr.ContentEncoding != null && wr.ContentEncoding.ToLower() == "gzip") //如果使用了GZip则先解压
|
if (wr.ContentEncoding != null && wr.ContentEncoding.ToLower() == "gzip") //如果使用了GZip则先解压
|
||||||
{
|
{
|
||||||
using (Stream streamReceive = wr.GetResponseStream())
|
using (Stream streamReceive = wr.GetResponseStream())
|
||||||
@@ -497,24 +551,38 @@ namespace N_m3u8DL_CLI
|
|||||||
if (shouldStop)
|
if (shouldStop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
reProcess:
|
||||||
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
|
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
|
||||||
request.Timeout = timeOut;
|
request.Timeout = timeOut;
|
||||||
request.ReadWriteTimeout = timeOut; //重要
|
request.ReadWriteTimeout = timeOut; //重要
|
||||||
request.AllowAutoRedirect = true;
|
request.AllowAutoRedirect = false; //手动处理重定向,否则会丢失Referer
|
||||||
request.KeepAlive = false;
|
request.KeepAlive = false;
|
||||||
request.Method = "GET";
|
request.Method = "GET";
|
||||||
if (NoProxy) request.Proxy = null;
|
if (NoProxy)
|
||||||
|
{
|
||||||
|
request.Proxy = null;
|
||||||
|
}
|
||||||
|
else if (UseProxyAddress != "")
|
||||||
|
{
|
||||||
|
WebProxy proxy = new WebProxy(UseProxyAddress);
|
||||||
|
//proxy.Credentials = new NetworkCredential(username, password);
|
||||||
|
request.Proxy = proxy;
|
||||||
|
}
|
||||||
if (url.Contains("data.video.iqiyi.com"))
|
if (url.Contains("data.video.iqiyi.com"))
|
||||||
request.UserAgent = "QYPlayer/Android/4.4.5;NetType/3G;QTP/1.1.4.3";
|
request.UserAgent = "QYPlayer/Android/4.4.5;NetType/3G;QTP/1.1.4.3";
|
||||||
else if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
else if (url.Contains("pcvideo") && url.Contains(".titan.mgtv.com"))
|
||||||
{
|
{
|
||||||
request.UserAgent = "";
|
request.UserAgent = "";
|
||||||
if (!url.Contains("/internettv/"))
|
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");
|
request.Headers.Add("Cookie", "MQGUID");
|
||||||
}
|
}
|
||||||
|
else if (url.Contains(".xboku.com/")) //独播库
|
||||||
|
{
|
||||||
|
request.Referer = "https://my.duboku.vip/static/player/videojs.html";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
request.UserAgent = "VLC/2.2.1 LibVLC/2.2.1";
|
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)
|
if (expectByte != -1)
|
||||||
request.AddRange("bytes", startByte, startByte + expectByte - 1);
|
request.AddRange("bytes", startByte, startByte + expectByte - 1);
|
||||||
@@ -548,6 +616,13 @@ namespace N_m3u8DL_CLI
|
|||||||
bool pngHeader = false; //PNG HEADER检测
|
bool pngHeader = false; //PNG HEADER检测
|
||||||
using (var response = (HttpWebResponse)request.GetResponse())
|
using (var response = (HttpWebResponse)request.GetResponse())
|
||||||
{
|
{
|
||||||
|
//302
|
||||||
|
if (response.Headers.Get("Location") != null)
|
||||||
|
{
|
||||||
|
url = response.Headers.Get("Location");
|
||||||
|
response.Close();
|
||||||
|
goto reProcess;
|
||||||
|
}
|
||||||
using (var responseStream = response.GetResponseStream())
|
using (var responseStream = response.GetResponseStream())
|
||||||
{
|
{
|
||||||
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
|
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Write))
|
||||||
@@ -556,10 +631,17 @@ namespace N_m3u8DL_CLI
|
|||||||
totalLen = response.ContentLength;
|
totalLen = response.ContentLength;
|
||||||
byte[] bArr = new byte[1024];
|
byte[] bArr = new byte[1024];
|
||||||
int size = responseStream.Read(bArr, 0, (int)bArr.Length);
|
int size = responseStream.Read(bArr, 0, (int)bArr.Length);
|
||||||
if (!pngHeader && size > 3 && 137 == bArr[0] && 80 == bArr[1] && 78 == bArr[2] && 71 == bArr[3]) ;
|
if (!pngHeader && size > 3 && 137 == bArr[0] && 80 == bArr[1] && 78 == bArr[2] && 71 == bArr[3])
|
||||||
{
|
{
|
||||||
pngHeader = true;
|
pngHeader = true;
|
||||||
}
|
}
|
||||||
|
//GIF HEADER检测
|
||||||
|
if (!pngHeader && size > 3 && 0x47 == bArr[0] && 0x49 == bArr[1] && 0x46 == bArr[2] && 0x38 == bArr[3])
|
||||||
|
{
|
||||||
|
bArr = bArr.Skip(42).ToArray();
|
||||||
|
size -= 42;
|
||||||
|
downLen += 42;
|
||||||
|
}
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
{
|
{
|
||||||
stream.Write(bArr, 0, size);
|
stream.Write(bArr, 0, size);
|
||||||
@@ -586,6 +668,7 @@ namespace N_m3u8DL_CLI
|
|||||||
try { File.Delete(path); } catch (Exception) { }
|
try { File.Delete(path); } catch (Exception) { }
|
||||||
if (pngHeader)
|
if (pngHeader)
|
||||||
TrySkipPngHeader(path);
|
TrySkipPngHeader(path);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -623,13 +706,13 @@ namespace N_m3u8DL_CLI
|
|||||||
}
|
}
|
||||||
else if (137 == u[0] && 80 == u[1] && 78 == u[2] && 71 == u[3])
|
else if (137 == u[0] && 80 == u[1] && 78 == u[2] && 71 == u[3])
|
||||||
{
|
{
|
||||||
//确定是PNG但是需要手动查询结尾标记(0x60 0x82 0x47)
|
//确定是PNG但是需要手动查询结尾标记 0x47 出现两次
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
for (int i = 4; i < u.Length - 3; i++)
|
for (int i = 4; i < u.Length - 188 * 2; i++)
|
||||||
{
|
{
|
||||||
if (u[i] == 0x60 && u[i + 1] == 0x82 && u[i + 2] == 0x47)
|
if (u[i] == 0x47 && u[i + 188] == 0x47 && u[i + 188 + 188] == 0x47)
|
||||||
{
|
{
|
||||||
skip = i + 2;
|
skip = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -805,6 +888,12 @@ namespace N_m3u8DL_CLI
|
|||||||
FFmpeg.UseAACFilter = true;
|
FFmpeg.UseAACFilter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//有非AAC音轨则关闭UseAACFilter
|
||||||
|
if (res.Contains("Audio") && !res.Contains("Audio aac"))
|
||||||
|
{
|
||||||
|
FFmpeg.UseAACFilter = false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((VIDEO_TYPE == "" || VIDEO_TYPE == "IGNORE") && res.Contains("Audio eac3"))
|
if ((VIDEO_TYPE == "" || VIDEO_TYPE == "IGNORE") && res.Contains("Audio eac3"))
|
||||||
{
|
{
|
||||||
AUDIO_TYPE = "eac3";
|
AUDIO_TYPE = "eac3";
|
||||||
@@ -1059,7 +1148,16 @@ namespace N_m3u8DL_CLI
|
|||||||
protected override WebRequest GetWebRequest(Uri address)
|
protected override WebRequest GetWebRequest(Uri address)
|
||||||
{
|
{
|
||||||
var wr = (HttpWebRequest)base.GetWebRequest(address);
|
var wr = (HttpWebRequest)base.GetWebRequest(address);
|
||||||
if (NoProxy) wr.Proxy = null;
|
if (NoProxy)
|
||||||
|
{
|
||||||
|
wr.Proxy = null;
|
||||||
|
}
|
||||||
|
else if (UseProxyAddress != "")
|
||||||
|
{
|
||||||
|
WebProxy proxy = new WebProxy(UseProxyAddress);
|
||||||
|
//proxy.Credentials = new NetworkCredential(username, password);
|
||||||
|
wr.Proxy = proxy;
|
||||||
|
}
|
||||||
if (setRange)
|
if (setRange)
|
||||||
wr.AddRange(this.from, this.to);
|
wr.AddRange(this.from, this.to);
|
||||||
if (setTimeout)
|
if (setTimeout)
|
||||||
|
|||||||
824
N_m3u8DL-CLI/MPDParser.cs
Normal file
824
N_m3u8DL-CLI/MPDParser.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<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')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -12,6 +13,8 @@
|
|||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
|
<NuGetPackageImportStamp>
|
||||||
|
</NuGetPackageImportStamp>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
@@ -38,6 +41,9 @@
|
|||||||
<ApplicationIcon>logo_3Iv_icon.ico</ApplicationIcon>
|
<ApplicationIcon>logo_3Iv_icon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<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="Microsoft.JScript" />
|
||||||
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
|
<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">
|
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
@@ -64,6 +70,7 @@
|
|||||||
<Compile Include="CommandLineArgumentParser.cs" />
|
<Compile Include="CommandLineArgumentParser.cs" />
|
||||||
<Compile Include="Decode51CtoKey.cs" />
|
<Compile Include="Decode51CtoKey.cs" />
|
||||||
<Compile Include="DecodeDdyun.cs" />
|
<Compile Include="DecodeDdyun.cs" />
|
||||||
|
<Compile Include="DecodeHuke88Key.cs" />
|
||||||
<Compile Include="DecodeImooc.cs" />
|
<Compile Include="DecodeImooc.cs" />
|
||||||
<Compile Include="DecodeNfmovies.cs" />
|
<Compile Include="DecodeNfmovies.cs" />
|
||||||
<Compile Include="Decrypter.cs" />
|
<Compile Include="Decrypter.cs" />
|
||||||
@@ -73,6 +80,7 @@
|
|||||||
<Compile Include="HLSTags.cs" />
|
<Compile Include="HLSTags.cs" />
|
||||||
<Compile Include="LOGGER.cs" />
|
<Compile Include="LOGGER.cs" />
|
||||||
<Compile Include="DownloadManager.cs" />
|
<Compile Include="DownloadManager.cs" />
|
||||||
|
<Compile Include="MPDParser.cs" />
|
||||||
<Compile Include="Parser.cs" />
|
<Compile Include="Parser.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
@@ -129,4 +137,12 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<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>
|
</Project>
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
333
N_m3u8DL-CLI/changelog.txt
Normal file
333
N_m3u8DL-CLI/changelog.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<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="Newtonsoft.Json" version="12.0.3" targetFramework="net46" />
|
||||||
<package id="NiL.JS" version="2.5.1428" targetFramework="net46" />
|
<package id="NiL.JS" version="2.5.1428" targetFramework="net46" />
|
||||||
</packages>
|
</packages>
|
||||||
22
N_m3u8DL-CLI/strings.Designer.cs
generated
22
N_m3u8DL-CLI/strings.Designer.cs
generated
@@ -47,8 +47,8 @@ namespace N_m3u8DL_CLI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重写当前线程的 CurrentUICulture 属性
|
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||||
/// 重写当前线程的 CurrentUICulture 属性。
|
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
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>
|
||||||
/// 查找类似 已关闭完整性检查 的本地化字符串。
|
/// 查找类似 已关闭完整性检查 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -493,6 +502,15 @@ namespace N_m3u8DL_CLI {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 开始解析MPD内容... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string startParsingMpd {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("startParsingMpd", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 重新解析m3u8... 的本地化字符串。
|
/// 查找类似 重新解析m3u8... 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -201,6 +201,7 @@
|
|||||||
--downloadRange Range Set range for a video
|
--downloadRange Range Set range for a video
|
||||||
--stopSpeed Number Speed below this, retry(KB/s)
|
--stopSpeed Number Speed below this, retry(KB/s)
|
||||||
--maxSpeed Number Set max download speed(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
|
--enableDelAfterDone Enable delete clips after download completed
|
||||||
--enableMuxFastStart Enable fast start for mp4
|
--enableMuxFastStart Enable fast start for mp4
|
||||||
--enableBinaryMerge Enable use binary merge instead ffmpeg
|
--enableBinaryMerge Enable use binary merge instead ffmpeg
|
||||||
@@ -298,4 +299,10 @@
|
|||||||
<data name="wrtingMeta" xml:space="preserve">
|
<data name="wrtingMeta" xml:space="preserve">
|
||||||
<value>Writing Json: [meta.json]</value>
|
<value>Writing Json: [meta.json]</value>
|
||||||
</data>
|
</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>
|
</root>
|
||||||
@@ -202,6 +202,7 @@
|
|||||||
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
|
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
|
||||||
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
||||||
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
||||||
|
--proxyAddress http://xx 设置HTTP代理, 如 http://127.0.0.1:8080
|
||||||
--enableDelAfterDone 开启下载后删除临时文件夹的功能
|
--enableDelAfterDone 开启下载后删除临时文件夹的功能
|
||||||
--enableMuxFastStart 开启混流mp4的FastStart特性
|
--enableMuxFastStart 开启混流mp4的FastStart特性
|
||||||
--enableBinaryMerge 开启二进制合并分片
|
--enableBinaryMerge 开启二进制合并分片
|
||||||
@@ -299,4 +300,10 @@
|
|||||||
<data name="wrtingMeta" xml:space="preserve">
|
<data name="wrtingMeta" xml:space="preserve">
|
||||||
<value>写出meta.json</value>
|
<value>写出meta.json</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="startParsingMpd" xml:space="preserve">
|
||||||
|
<value>开始解析MPD内容...</value>
|
||||||
|
</data>
|
||||||
|
<data name="checkingLast" xml:space="preserve">
|
||||||
|
<value>正在判断尾分片是否有效...</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -202,6 +202,7 @@
|
|||||||
--liveRecDur HH:MM:SS 直播錄制時,達到此長度自動退出軟件
|
--liveRecDur HH:MM:SS 直播錄制時,達到此長度自動退出軟件
|
||||||
--stopSpeed Number 當速度低於此值時,重試(單位為KB/s)
|
--stopSpeed Number 當速度低於此值時,重試(單位為KB/s)
|
||||||
--maxSpeed Number 設置下載速度上限(單位為KB/s)
|
--maxSpeed Number 設置下載速度上限(單位為KB/s)
|
||||||
|
--proxyAddress http://xx 設置HTTP代理, 如 http://127.0.0.1:8080
|
||||||
--enableDelAfterDone 開啟下載後刪除臨時文件夾的功能
|
--enableDelAfterDone 開啟下載後刪除臨時文件夾的功能
|
||||||
--enableMuxFastStart 開啟混流mp4的FastStart特性
|
--enableMuxFastStart 開啟混流mp4的FastStart特性
|
||||||
--enableBinaryMerge 開啟二進制合並分片
|
--enableBinaryMerge 開啟二進制合並分片
|
||||||
@@ -299,4 +300,10 @@
|
|||||||
<data name="wrtingMeta" xml:space="preserve">
|
<data name="wrtingMeta" xml:space="preserve">
|
||||||
<value>寫出meta.json</value>
|
<value>寫出meta.json</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="startParsingMpd" xml:space="preserve">
|
||||||
|
<value>開始解析MPD內容...</value>
|
||||||
|
</data>
|
||||||
|
<data name="checkingLast" xml:space="preserve">
|
||||||
|
<value>正在判斷尾分片是否有效...</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -18,9 +18,7 @@
|
|||||||
本项目已与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
|
# N_m3u8DL-CLI
|
||||||
一个**简单易用的**m3u8下载器,下载地址:https://github.com/nilaoda/N_m3u8DL-CLI/releases
|
一个**简单易用的**m3u8下载器,下载地址:https://github.com/nilaoda/N_m3u8DL-CLI/releases
|
||||||
@@ -48,7 +46,7 @@
|
|||||||
|
|
||||||
# 命令行选项
|
# 命令行选项
|
||||||
```
|
```
|
||||||
N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
|
N_m3u8DL-CLI.exe <URL|File|JSON> [OPTIONS]
|
||||||
|
|
||||||
--workDir Directory 设定程序工作目录
|
--workDir Directory 设定程序工作目录
|
||||||
--saveName Filename 设定存储文件名(不包括后缀)
|
--saveName Filename 设定存储文件名(不包括后缀)
|
||||||
@@ -66,6 +64,7 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
|
|||||||
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
|
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
|
||||||
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
|
||||||
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
--maxSpeed Number 设置下载速度上限(单位为KB/s)
|
||||||
|
--proxyAddress http://xx 设置HTTP代理, 如 http://127.0.0.1:8080
|
||||||
--enableDelAfterDone 开启下载后删除临时文件夹的功能
|
--enableDelAfterDone 开启下载后删除临时文件夹的功能
|
||||||
--enableMuxFastStart 开启混流mp4的FastStart特性
|
--enableMuxFastStart 开启混流mp4的FastStart特性
|
||||||
--enableBinaryMerge 开启二进制合并分片
|
--enableBinaryMerge 开启二进制合并分片
|
||||||
@@ -81,4 +80,4 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
|
|||||||
https://nilaoda.github.io/N_m3u8DL-CLI/
|
https://nilaoda.github.io/N_m3u8DL-CLI/
|
||||||
|
|
||||||
# 赞赏
|
# 赞赏
|
||||||
https://nilaoda.github.io/N_m3u8DL-CLI/source/images/alipay.png
|

|
||||||
|
|||||||
@@ -47,6 +47,7 @@ N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
|
|||||||
--downloadRange Range Set range for a video
|
--downloadRange Range Set range for a video
|
||||||
--stopSpeed Number Speed below this, retry(KB/s)
|
--stopSpeed Number Speed below this, retry(KB/s)
|
||||||
--maxSpeed Number Set max download speed(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
|
--enableDelAfterDone Enable delete clips after download completed
|
||||||
--enableMuxFastStart Enable fast start for mp4
|
--enableMuxFastStart Enable fast start for mp4
|
||||||
--enableBinaryMerge Enable use binary merge instead ffmpeg
|
--enableBinaryMerge Enable use binary merge instead ffmpeg
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
555
docs/GetM3u8.html
Normal file
555
docs/GetM3u8.html
Normal file
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