You've already forked N_m3u8DL-CLI
mirror of
https://github.com/nilaoda/N_m3u8DL-CLI
synced 2025-09-07 02:45:59 +02:00
Compare commits
142 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
faf67cd527 | ||
![]() |
38d1a1a2dc | ||
![]() |
12eb68d592 | ||
![]() |
0804e295e5 | ||
![]() |
847c4683cb | ||
![]() |
8c72947860 | ||
![]() |
f0b240a6ee | ||
![]() |
793cf53042 | ||
![]() |
612fc29197 | ||
![]() |
307e2389de | ||
![]() |
1c932abdc3 | ||
![]() |
314f0065c7 | ||
![]() |
59060bb74d | ||
![]() |
cab882c3a3 | ||
![]() |
9955532ce5 | ||
![]() |
7e127be8c2 | ||
![]() |
b46571a57f | ||
![]() |
da5861d907 | ||
![]() |
92bc91a1fb | ||
![]() |
439f50103e | ||
![]() |
8a95e31b2f | ||
![]() |
115b8a156a | ||
![]() |
120bcaebb5 | ||
![]() |
455d56707c | ||
![]() |
048adcf118 | ||
![]() |
fe5aa27b1c | ||
![]() |
039aa489b1 | ||
![]() |
14e80f0b06 | ||
![]() |
2256fff549 | ||
![]() |
84cfd4e138 | ||
![]() |
e70c229135 | ||
![]() |
8b520d0c19 | ||
![]() |
71d69de51a | ||
![]() |
bc89ead00d | ||
![]() |
ae79d6eb3a | ||
![]() |
96bd8af883 | ||
![]() |
89b1e30e0f | ||
![]() |
7a741359ab | ||
![]() |
564b6ad291 | ||
![]() |
a0fc9404f7 | ||
![]() |
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 | ||
![]() |
e700edba56 | ||
![]() |
aad948da7c | ||
![]() |
14f7b20176 | ||
![]() |
a66a9a4096 | ||
![]() |
c862f23a9c | ||
![]() |
1a722e80de | ||
![]() |
eff43e8ac3 | ||
![]() |
7648f8f8dc | ||
![]() |
1edc1a43fe |
34
.github/workflows/build_latest.yml
vendored
Normal file
34
.github/workflows/build_latest.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Build_Latest
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
name: Checkout Code
|
||||
|
||||
- name: Setup MSBuild Path
|
||||
uses: warrenbuckley/Setup-MSBuild@v1
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||
|
||||
- name: Setup NuGet
|
||||
uses: NuGet/setup-nuget@v1.0.2
|
||||
env:
|
||||
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
|
||||
|
||||
- name: Restore NuGet Packages
|
||||
run: nuget restore N_m3u8DL-CLI.sln
|
||||
|
||||
- name: Build
|
||||
run: msbuild N_m3u8DL-CLI.sln /p:Configuration=Release /p:DebugSymbols=false /p:DebugType=None
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v1.0.0
|
||||
with:
|
||||
name: N_m3u8DL-CLI_latest
|
||||
path: N_m3u8DL-CLI\bin\Release\N_m3u8DL-CLI.exe
|
41
N_m3u8DL-CLI/DecodeDdyun.cs
Normal file
41
N_m3u8DL-CLI/DecodeDdyun.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace N_m3u8DL_CLI
|
||||
{
|
||||
class DecodeDdyun
|
||||
{
|
||||
public static string DecryptM3u8(byte[] byteArray)
|
||||
{
|
||||
string tmp = DecodeNfmovies.DecryptM3u8(byteArray);
|
||||
if (tmp.StartsWith("duoduo.key"))
|
||||
{
|
||||
tmp = Regex.Replace(tmp, @"#EXT-X-BYTERANGE:.*\s", "");
|
||||
tmp = tmp.Replace("https:", "jump/https:")
|
||||
.Replace("inews.gtimg.com", "puui.qpic.cn");
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//https://player.ddyunp.com/jQuery.min.js?v1.5
|
||||
public static string GetVaildM3u8Url(string url)
|
||||
{
|
||||
//url: https://hls.ddyunp.com/ddyun/id/1/key/playlist.m3u8
|
||||
string id = Regex.Match(url, @"\w{20,}").Value;
|
||||
string tm = Global.GetTimeStamp(false);
|
||||
string t = ((long.Parse(tm) / 0x186a0) * 0x64).ToString();
|
||||
string tmp = id + "duoduo" + "1" + t;
|
||||
MD5 md5 = MD5.Create();
|
||||
byte[] bs = Encoding.UTF8.GetBytes(tmp);
|
||||
byte[] hs = md5.ComputeHash(bs);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (byte b in hs)
|
||||
{
|
||||
sb.Append(b.ToString("x2"));
|
||||
}
|
||||
string key = sb.ToString();
|
||||
return Regex.Replace(url, @"1/\w{20,}", "1/" + key);
|
||||
}
|
||||
}
|
||||
}
|
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;
|
||||
}
|
||||
}
|
||||
}
|
36
N_m3u8DL-CLI/DecodeNfmovies.cs
Normal file
36
N_m3u8DL-CLI/DecodeNfmovies.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace N_m3u8DL_CLI
|
||||
{
|
||||
class DecodeNfmovies
|
||||
{
|
||||
//https://jx.nfmovies.com/hls.min.js
|
||||
public static string DecryptM3u8(byte[] byteArray)
|
||||
{
|
||||
var t = byteArray;
|
||||
var decrypt = "";
|
||||
if (137 == t[0] && 80 == t[1] && 130 == t[354] && 96 == t[353]) t = t.Skip(355).ToArray();
|
||||
else
|
||||
{
|
||||
if (137 != t[0] || 80 != t[1] || 130 != t[394] || 96 != t[393])
|
||||
{
|
||||
for (var i = 0; i < t.Length; i++) decrypt += Convert.ToChar(t[i]);
|
||||
return decrypt;
|
||||
}
|
||||
t = t.Skip(395).ToArray();
|
||||
}
|
||||
using (var zipStream =
|
||||
new System.IO.Compression.GZipStream(new MemoryStream(t), System.IO.Compression.CompressionMode.Decompress))
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(zipStream, Encoding.UTF8))
|
||||
{
|
||||
decrypt = sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
return decrypt;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
@@ -10,19 +10,20 @@ namespace N_m3u8DL_CLI
|
||||
{
|
||||
class FFmpeg
|
||||
{
|
||||
private static string outPutPath = string.Empty;
|
||||
private static string reportFile = string.Empty;
|
||||
private static bool useAACFilter = false; //是否启用滤镜
|
||||
private static bool writeDate = 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 string FFMPEG_PATH = "ffmpeg";
|
||||
public static string REC_TIME = ""; //录制日期
|
||||
|
||||
public static string OutPutPath { get; set; } = string.Empty;
|
||||
public static string ReportFile { get; set; } = string.Empty;
|
||||
public static bool UseAACFilter { get; set; } = false; //是否启用滤镜
|
||||
public static bool WriteDate { get; set; } = true; //是否写入录制日期
|
||||
|
||||
public static void Merge(string[] files, string muxFormat, bool fastStart,
|
||||
string poster = "", string audioName = "", string title = "",
|
||||
string copyright = "", string comment = "", string encodingTool = "")
|
||||
{
|
||||
string dateString = string.IsNullOrEmpty(REC_TIME) ? DateTime.Now.ToString("o") : REC_TIME;
|
||||
|
||||
//同名文件已存在的共存策略
|
||||
if (File.Exists($"{OutPutPath}.{muxFormat.ToLower()}"))
|
||||
{
|
||||
@@ -50,7 +51,7 @@ namespace N_m3u8DL_CLI
|
||||
command += " " + (string.IsNullOrEmpty(ddpAudio) ? "" : "-i \"" + ddpAudio + "\"");
|
||||
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)
|
||||
+ (writeDate ? " -metadata date=\"" + DateTime.Now.ToString("o") + "\"" : "") +
|
||||
+ (WriteDate ? " -metadata date=\"" + dateString + "\"" : "") +
|
||||
" -metadata encoding_tool=\"" + encodingTool + "\" -metadata title=\"" + title +
|
||||
"\" -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 + "\" ";
|
||||
@@ -83,7 +84,7 @@ namespace N_m3u8DL_CLI
|
||||
|
||||
}
|
||||
|
||||
Run("ffmpeg", command, Path.GetDirectoryName(files[0]));
|
||||
Run(FFMPEG_PATH, command, Path.GetDirectoryName(files[0]));
|
||||
LOGGER.WriteLine(strings.ffmpegDone);
|
||||
//Console.WriteLine(command);
|
||||
}
|
||||
@@ -92,7 +93,7 @@ namespace N_m3u8DL_CLI
|
||||
{
|
||||
if (Global.VIDEO_TYPE == "H264")
|
||||
{
|
||||
Run("ffmpeg",
|
||||
Run(FFMPEG_PATH,
|
||||
"-loglevel quiet -i \"" + file + "\" -map 0 -c copy -copy_unknown -f mpegts -bsf:v h264_mp4toannexb \""
|
||||
+ Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts\"",
|
||||
Path.GetDirectoryName(file));
|
||||
@@ -104,7 +105,7 @@ namespace N_m3u8DL_CLI
|
||||
}
|
||||
else if (Global.VIDEO_TYPE == "H265")
|
||||
{
|
||||
Run("ffmpeg",
|
||||
Run(FFMPEG_PATH,
|
||||
"-loglevel quiet -i \"" + file + "\" -map 0 -c copy -copy_unknown -f mpegts -bsf:v hevc_mp4toannexb \""
|
||||
+ Path.GetFileNameWithoutExtension(file) + "[MPEGTS].ts\"",
|
||||
Path.GetDirectoryName(file));
|
||||
|
File diff suppressed because it is too large
Load Diff
116
N_m3u8DL-CLI/IqJsonParser.cs
Normal file
116
N_m3u8DL-CLI/IqJsonParser.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
836
N_m3u8DL-CLI/MPDParser.cs
Normal file
836
N_m3u8DL-CLI/MPDParser.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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,19 +42,30 @@
|
||||
<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">
|
||||
<HintPath>..\packages\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NiL.JS, Version=2.5.1428.0, Culture=neutral, PublicKeyToken=fa941a7c2a4de689, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NiL.JS.dll</HintPath>
|
||||
<HintPath>..\packages\NiL.JS.2.5.1428\lib\net45\NiL.JS.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="PresentationFramework" />
|
||||
<Reference Include="System" />
|
||||
<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" />
|
||||
@@ -63,17 +78,39 @@
|
||||
<Compile Include="CommandLineArgument.cs" />
|
||||
<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" />
|
||||
<Compile Include="FFmpeg.cs" />
|
||||
<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">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>strings.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="strings.en-US.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>strings.en-US.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="strings.zh-TW.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>strings.zh-TW.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Watcher.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -82,9 +119,6 @@
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="bin\Debug\Newtonsoft.Json.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="Scripting">
|
||||
<Guid>{420B2830-E718-11CF-893D-00A0C9054228}</Guid>
|
||||
@@ -100,16 +134,27 @@
|
||||
<Content Include="logo_3Iv_icon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<EmbeddedResource Include="strings.en-US.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<LastGenOutput>strings.en-US.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="strings.en-US.resx" />
|
||||
<EmbeddedResource Include="strings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>strings.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="strings.zh-TW.resx" />
|
||||
<EmbeddedResource Include="strings.zh-TW.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>strings.zh-TW.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
<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
30
N_m3u8DL-CLI/ProgressReporter.cs
Normal file
30
N_m3u8DL-CLI/ProgressReporter.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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.8.0")]
|
||||
[assembly: AssemblyFileVersion("2.9.8.0")]
|
||||
|
@@ -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, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
362
N_m3u8DL-CLI/changelog.txt
Normal file
362
N_m3u8DL-CLI/changelog.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +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>
|
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>
|
||||
/// 重写当前线程的 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>
|
||||
|
@@ -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>
|
@@ -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>
|
@@ -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>
|
22
README.md
22
README.md
@@ -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
|
||||

|
||||
|
@@ -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
|
||||
|
||||

|
||||
|
||||
@@ -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
559
docs/GetM3u8.html
Normal file
559
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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user