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

Compare commits

..

182 Commits
2.7.2 ... 3.0.2

Author SHA1 Message Date
nilaoda
f5a9ed08a1 update version 2022-07-12 00:21:39 +08:00
nilaoda
6b8bfde19f update docs 2022-07-12 00:10:53 +08:00
nilaoda
ff738f2849 Merge pull request #698 from xifangczy/master
fix: 修正m3u8dl协议 转义符问题
2022-07-11 23:44:31 +08:00
O2bmm
3d35c24a2e fix: 修正m3u8dl协议 转义符问题 2022-07-11 01:32:30 +08:00
nilaoda
41d7151e7e Update HLSLiveDownloader.cs 2022-06-22 11:43:36 +08:00
nilaoda
94246ef163 支持ChaCha20解密 2022-06-20 23:18:27 +08:00
nilaoda
9c118631cf 优化对#EXT-X-BYTERANGE的处理 2022-06-05 02:15:24 +08:00
nilaoda
2ee9ab234f fix #665 #661 2022-05-26 20:18:05 +08:00
nilaoda
606f2184df 修正对于m3u8dl://的描述 2022-05-26 01:26:18 +08:00
nilaoda
7dd2b6cee2 update doc 2022-05-24 15:24:22 +08:00
nilaoda
f744aa990e 3.0.0 2022-05-24 14:41:44 +08:00
nilaoda
97c9f444b8 Update HLSLiveDownloader.cs 2022-05-24 14:39:33 +08:00
nilaoda
8aac37bbe2 去除无效处理 2022-05-24 14:11:47 +08:00
nilaoda
b7e19ec699 elearning cdeledu 2022-05-19 21:10:35 +08:00
nilaoda
7e7c5c6ba9 kkbox.com.tw 2022-05-10 19:55:44 +08:00
nilaoda
50722079ba 处理BMP HEADER 2022-05-08 20:15:00 +08:00
nilaoda
d529ece032 读取在MPD开头定义的<BaseURL>,并替换本身的URL 2022-05-03 22:47:26 +08:00
nilaoda
9ed8b359a1 fix kakao.com 2022-04-22 23:49:40 +08:00
nilaoda
a7591e3978 Merge pull request #640 from abevol/add-uri-support
添加对m3u8dl链接协议的支持
2022-04-13 22:44:19 +08:00
abevol
094a89bc79 添加对m3u8dl链接协议的支持 2022-04-13 20:03:27 +08:00
nilaoda
9e7b603d3b Merge pull request #623 from bxb100/master
fix: GitHub action can't use windowWidth
2022-03-14 11:02:23 +08:00
John Bi
3801090928 fix: github action can't using windowWidth 2022-03-14 01:23:41 +08:00
nilaoda
42c1d628d4 ... 2022-03-10 22:56:37 +08:00
nilaoda
ecefecd827 fix #619 2022-03-10 22:12:23 +08:00
nilaoda
4661818c1f better init info 2021-12-13 17:45:35 +08:00
nilaoda
fa61cd136d update help text 2021-12-13 17:44:58 +08:00
nilaoda
472fb0cf02 Merge pull request #571 from Mtcno/master
添加socks5代理,引用HttpToSocks5Proxy
2021-12-13 17:36:19 +08:00
nilaoda
28e39a94ac Delete FodyWeavers.xsd 2021-12-13 17:35:43 +08:00
nilaoda
a42ade64f3 Delete FodyWeavers.xml 2021-12-13 17:35:19 +08:00
Mtcno
539f773e37 添加sock5代理,引用HttpToSocks5Proxy 2021-12-13 00:50:14 +08:00
nilaoda
d6f27cf90f update docs 2021-12-07 22:31:46 +08:00
nilaoda
8912ee5e4b 优化杜比视界判断 2021-12-07 22:28:27 +08:00
nilaoda
409437b2c7 WriteInit 2021-11-29 01:29:54 +08:00
nilaoda
350d3b508d Update Program.cs 2021-11-26 14:32:26 +08:00
nilaoda
1e3f06eaae del useless files 2021-11-26 12:26:47 +08:00
nilaoda
2d4bc42d55 handle empty cmd 2021-11-26 12:23:19 +08:00
nilaoda
68e06d3fa7 Change to CommandLineParser 2021-11-26 12:14:25 +08:00
nilaoda
6c3340e94e 2.9.9 2021-11-23 15:22:09 +08:00
nilaoda
051faa9f2b 修复重试失效问题 2021-11-23 14:37:50 +08:00
nilaoda
115f9c9424 update image 2021-11-20 10:52:01 +08:00
nilaoda
faf67cd527 2.9.8 2021-11-20 10:14:31 +08:00
nilaoda
38d1a1a2dc 修正init url缺失baseurl问题 2021-11-12 23:28:35 +08:00
nilaoda
12eb68d592 修复日志冲突问题 2021-10-19 11:14:41 +08:00
nilaoda
0804e295e5 修复流选择的显示bug 2021-10-19 10:53:03 +08:00
nilaoda
847c4683cb update wetv js 2021-10-17 00:51:46 +08:00
nilaoda
8c72947860 package exe only 2021-10-17 00:24:34 +08:00
nilaoda
f0b240a6ee 优化AppleTV处理 2021-09-05 19:21:08 +08:00
nilaoda
793cf53042 解决同一个period且同id导致被重复添加分片 2021-09-05 18:17:05 +08:00
nilaoda
612fc29197 修复padding负值问题 2021-09-02 22:41:16 +08:00
nilaoda
307e2389de Update README.md 2021-09-02 10:46:11 +08:00
nilaoda
1c932abdc3 Update AssemblyInfo.cs 2021-08-23 11:38:19 +08:00
nilaoda
314f0065c7 fix node select bug and type show bug #496 2021-08-23 11:35:14 +08:00
nilaoda
59060bb74d Merge pull request #495 from ncnnnnn/patch-2
Update README.md
2021-08-21 22:30:13 +08:00
ncnnnnn
cab882c3a3 Update README.md 2021-08-21 20:35:02 +08:00
nilaoda
9955532ce5 强校验MAP下载成功 2021-08-15 20:18:06 +08:00
nilaoda
7e127be8c2 初步修改显示输出样式 2021-08-15 15:32:01 +08:00
nilaoda
b46571a57f Merge pull request #470 from CW-B-W/master
Fix typos in README_ENG.md
2021-07-18 02:28:52 +08:00
Chiao-Wei Wang
da5861d907 Update README_ENG.md 2021-07-18 01:57:16 +08:00
nilaoda
92bc91a1fb drm-json to m3u8 2021-07-04 00:40:05 +08:00
nilaoda
439f50103e 1.支持iq-drm格式json自动转换 2.优化master选择最高清晰度逻辑 2021-07-04 00:38:17 +08:00
nilaoda
8a95e31b2f update docs 2021-07-03 22:35:00 +08:00
nilaoda
115b8a156a Update packages.config 2021-06-27 23:06:33 +08:00
nilaoda
120bcaebb5 Update N_m3u8DL-CLI.csproj 2021-06-27 23:01:22 +08:00
nilaoda
455d56707c Update N_m3u8DL-CLI.csproj 2021-06-27 22:55:05 +08:00
nilaoda
048adcf118 支持解压brotli 2021-06-27 22:41:12 +08:00
nilaoda
fe5aa27b1c 修正判断png图片时可能出现的数组越界bug 2021-06-27 22:39:16 +08:00
nilaoda
039aa489b1 优化范围选择结尾识别 2021-06-27 22:38:32 +08:00
nilaoda
14e80f0b06 优化输出并增加ETA显示 2021-03-27 14:04:31 +08:00
nilaoda
2256fff549 日志文件初始化时,精确到毫秒防止重复 2021-03-27 14:03:54 +08:00
nilaoda
84cfd4e138 Update README_ENG.md 2021-03-26 09:35:28 +08:00
nilaoda
e70c229135 Update README.md 2021-03-26 09:30:30 +08:00
nilaoda
8b520d0c19 修正AppleTV逻辑 2021-03-25 23:11:18 +08:00
nilaoda
71d69de51a Update changelog.txt 2021-03-25 22:09:44 +08:00
nilaoda
bc89ead00d 为下载分片增加了自动重试机制(3次) 2021-03-25 22:09:26 +08:00
nilaoda
ae79d6eb3a 优化下载监控 2021-03-25 22:07:04 +08:00
nilaoda
96bd8af883 适配AppleTv资源 2021-03-22 23:18:22 +08:00
nilaoda
89b1e30e0f 修复enableAudioOnly且下载MPD文件时留下冗余(Audio)文件夹的情况 2021-03-22 23:17:09 +08:00
nilaoda
7a741359ab Update README.md 2021-03-04 13:17:07 +08:00
nilaoda
564b6ad291 Update README_ENG.md 2021-03-04 13:12:06 +08:00
nilaoda
a0fc9404f7 Update README.md 2021-03-04 13:11:06 +08:00
nilaoda
5267be1699 Update changelog.txt 2021-03-04 12:26:20 +08:00
nilaoda
20bfda39e7 bug fix
- 修复M3U8选择音轨/字幕不生效问题
  - 外挂音轨时enableAudioOnly可仅下载音频
2021-03-04 12:23:51 +08:00
nilaoda
ba4c0eeda7 Update Program.cs 2021-02-22 11:58:52 +08:00
nilaoda
5d72e24002 update docs 2021-02-22 11:16:45 +08:00
nilaoda
a87c051d23 update readme 2021-02-22 11:00:32 +08:00
nilaoda
44e1b68d6b update help info 2021-02-22 10:57:53 +08:00
nilaoda
e65dfa52cd Merge pull request #375 from evanlabs/master
添加用户网络代理支持,使用--proxyAddress指定代理地址。
2021-02-22 10:49:42 +08:00
EvanYeung
965c173899 添加用户网络代理支持,使用--proxyAddress指定代理地址。 2021-02-22 09:50:18 +08:00
nilaoda
880af02cc2 打印MPD解析日志 2021-02-21 15:13:44 +08:00
nilaoda
2742de43c4 增加键值 2021-02-21 15:13:07 +08:00
nilaoda
9d8cb57390 MPD检测最后一个分片是否有效 2021-02-21 13:24:15 +08:00
nilaoda
9e2a192dab Update changelog.txt 2021-02-21 13:23:57 +08:00
nilaoda
33cf9e2256 Update Parser.cs 2021-02-11 17:06:19 +08:00
nilaoda
2959cbbb5c Update changelog.txt 2021-02-11 17:06:08 +08:00
nilaoda
c2eb8a6adc 修正MPD拼接BaseUrl逻辑 2021-02-10 22:32:06 +08:00
nilaoda
e1b591b81c Update N_m3u8DL-CLI.csproj 2021-02-03 11:54:02 +08:00
nilaoda
334b1939b5 修复气球云;优化独播库 2021-02-03 00:38:57 +08:00
nilaoda
7e916b65fd Update changelog.txt 2021-02-01 22:57:37 +08:00
nilaoda
4ead563fa2 修正自定义KEY切存在IV时的隐患 2021-02-01 22:57:27 +08:00
nilaoda
1b387a06e5 update docs 2021-02-01 22:52:07 +08:00
nilaoda
6e7b4ac7ea ddyun识别90mm 2021-02-01 22:42:56 +08:00
nilaoda
e98c5205d1 优化跳过png的算法 2021-02-01 14:18:03 +08:00
nilaoda
d7890dd124 优化跳过png的算法 2021-02-01 14:11:28 +08:00
nilaoda
82f2111522 update 2021-01-24 16:26:32 +08:00
nilaoda
4c3207586f Update MPDParser.cs 2021-01-24 16:24:03 +08:00
nilaoda
69b411e37c fix sub merge bug 2021-01-24 16:22:13 +08:00
nilaoda
1e8525041f Download from DSNP 2021-01-24 16:21:32 +08:00
nilaoda
65ae72d4a4 Update MPDParser.cs 2021-01-18 20:36:43 +08:00
nilaoda
4a4bfae5ab 优化MPD下载行为 2021-01-18 02:00:19 +08:00
nilaoda
d586dddfcd Update changelog.txt 2021-01-18 01:59:31 +08:00
nilaoda
fca6b3ff6c Update changelog.txt 2020-12-29 23:19:39 +08:00
nilaoda
5d75626a36 Update Global.cs 2020-12-29 23:18:16 +08:00
nilaoda
a94271c244 mpd - xigua 2020-12-20 18:53:40 +08:00
nilaoda
c51118dce7 解密huke88 2020-12-20 18:53:02 +08:00
nilaoda
81b2e87bf7 处理同一ID分散在不同Period的情况 2020-12-12 02:07:41 +08:00
nilaoda
71a9878aaa Update changelog.txt 2020-12-06 21:32:48 +08:00
nilaoda
769fe4e926 Update Global.cs 2020-12-06 21:32:38 +08:00
nilaoda
1f57ba7c09 Update Parser.cs 2020-12-06 21:32:29 +08:00
nilaoda
71282bda30 Update N_m3u8DL-CLI.csproj 2020-12-02 20:35:44 +08:00
nilaoda
41ee8aebdf update project 2020-12-02 20:31:44 +08:00
nilaoda
a4537bc093 del xml 2020-12-02 20:23:50 +08:00
nilaoda
b8a60b3917 Update packages.config 2020-12-02 20:23:36 +08:00
nilaoda
8091dd290f Update N_m3u8DL-CLI.csproj 2020-12-02 20:15:29 +08:00
nilaoda
d48e84e611 Update FodyWeavers.xml 2020-12-02 20:10:29 +08:00
nilaoda
9f5423a437 Costura.Fody 2020-12-02 19:56:20 +08:00
nilaoda
ce7e38770a Update N_m3u8DL-CLI.csproj 2020-12-02 19:51:29 +08:00
nilaoda
8fdb2e918e Update packages.config 2020-12-02 19:49:10 +08:00
nilaoda
d4b7d240c1 修正多语言识别问题 2020-12-02 11:56:46 +08:00
nilaoda
484d2941ed Update Global.cs 2020-12-02 11:56:17 +08:00
nilaoda
a0f2b66575 Update changelog.txt 2020-12-02 11:56:04 +08:00
nilaoda
65cc0681e2 Update changelog.txt 2020-11-26 21:02:04 +08:00
nilaoda
7d980ec9a2 Update Global.cs 2020-11-26 21:01:57 +08:00
nilaoda
ec5892c05a 修复可能存在的溢出问题 2020-11-26 21:01:48 +08:00
nilaoda
9aed50fbf9 优化MPD识别 2020-11-26 21:01:03 +08:00
nilaoda
d657b455cd BUG FIX 2020-11-25 21:16:41 +08:00
nilaoda
cda6575605 BUG FIX 2020-11-25 21:16:18 +08:00
nilaoda
0d6377d41b Update changelog.txt 2020-11-25 17:34:53 +08:00
nilaoda
9c76bdcbce 支持选择音轨 2020-11-25 17:34:12 +08:00
nilaoda
83915ff606 Update Global.cs 2020-11-25 14:12:46 +08:00
nilaoda
9cd4746f33 Update changelog.txt 2020-11-25 14:11:31 +08:00
nilaoda
33a5b917ac 修正MPD判断最高清晰度的逻辑 2020-11-25 14:08:40 +08:00
nilaoda
f69978bd82 修改芒果TV请求头 2020-11-23 21:53:41 +08:00
nilaoda
d9fd526886 Update changelog.txt 2020-11-23 21:53:26 +08:00
nilaoda
1cc8ecfaaf Update Global.cs 2020-11-23 21:30:12 +08:00
nilaoda
2bc2dde2ad 修改默认UA 2020-11-23 21:29:48 +08:00
nilaoda
c3ddcf9e0e Update Program.cs 2020-11-23 21:29:31 +08:00
nilaoda
ba5d20dd02 Update Parser.cs 2020-11-23 21:29:03 +08:00
nilaoda
16f705fe66 Update Global.cs 2020-11-22 23:13:59 +08:00
nilaoda
d141cabc4a Update changelog.txt 2020-11-22 23:08:51 +08:00
nilaoda
adcf884a93 新的任务监控逻辑 2020-11-22 23:08:33 +08:00
nilaoda
9d903a025f Update DownloadManager.cs 2020-11-22 22:36:21 +08:00
nilaoda
0bd23ab641 更新版本号 2020-11-22 18:48:54 +08:00
nilaoda
a38f27ccd7 手动处理重定向
解决HTTPS协议自动重定向后,Referer丢失问题
2020-11-22 18:29:40 +08:00
nilaoda
3acec5efd3 Update Global.cs 2020-11-22 15:40:47 +08:00
nilaoda
90874e4bfe Update Parser.cs 2020-11-22 14:30:41 +08:00
nilaoda
b94768e3e8 修复自定义MPD的BaseURL 2020-11-22 00:40:17 +08:00
nilaoda
311f3b882e 更新版本号 2020-11-21 19:36:04 +08:00
nilaoda
4b4f537984 BUG FIX 2020-11-21 19:34:47 +08:00
nilaoda
8032d50b42 传递MPD_URL时处理302 2020-11-21 19:34:27 +08:00
nilaoda
f615764e55 Update build_latest.yml 2020-11-21 13:48:20 +08:00
nilaoda
ccaa200ef8 Update build_latest.yml 2020-11-21 13:45:56 +08:00
nilaoda
6058d878eb Update N_m3u8DL-CLI.csproj 2020-11-21 13:40:15 +08:00
nilaoda
c712c6dee0 Create changelog.txt 2020-11-21 13:30:56 +08:00
nilaoda
bb24bb998f Update Global.cs 2020-11-21 13:11:15 +08:00
nilaoda
e9d951efa5 检测GIF HEADER 2020-11-21 12:25:01 +08:00
nilaoda
6f88a805ef 修复PNG检测逻辑
多写了一个分号……
2020-11-21 12:08:28 +08:00
nilaoda
6aa6d63a8d Convert MPD to M3U8
通过将MPD转换为m3u8进行下载
2020-11-20 23:34:35 +08:00
nilaoda
147246caba Update Parser.cs 2020-11-18 16:05:18 +08:00
nilaoda
35c1ee4777 Update Parser.cs 2020-11-18 15:52:36 +08:00
nilaoda
8b32081b85 识别m3u8文件中的EXT-X-PROGRAM-DATE-TIME 2020-11-18 15:33:39 +08:00
nilaoda
c00de328d1 修改默认UA 修改音轨判断逻辑
修改UA为Mozilla/5.0 (Linux; U; Android 7.0; zh-cn; 15 Plus Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/9.4 Mobile Safari/537.36

修改AAC滤镜的使用逻辑

当m3u8文本大小大于50MB时应当放弃
2020-11-18 15:03:21 +08:00
nilaoda
d5193c1645 fix bug 2020-11-06 22:11:21 +08:00
nilaoda
c06fbf5820 update docs 2020-11-03 11:38:24 +08:00
nilaoda
e700edba56 Update Program.cs
修正处理文件名过长的逻辑
2020-10-14 22:18:56 +08:00
nilaoda
aad948da7c v2.7.5 2020-10-14 22:01:03 +08:00
nilaoda
14f7b20176 Merge pull request #246 from Suwmlee/master
Fix build error
2020-09-22 10:19:45 +08:00
Mathhew
a66a9a4096 Fix build error 2020-09-22 09:49:58 +08:00
nilaoda
c862f23a9c v2.7.4
支持ddyun m3u8解密
2020-09-20 13:41:49 +08:00
nilaoda
1a722e80de Delete DecryptNfmovies.cs 2020-09-20 13:41:02 +08:00
nilaoda
eff43e8ac3 Merge pull request #240 from Suwmlee/master
Add github action
2020-09-17 18:58:30 +08:00
Mathhew
7648f8f8dc Add github action 2020-09-17 10:05:35 +08:00
nilaoda
1edc1a43fe v2.7.3 2020-09-14 21:53:51 +08:00
71 changed files with 4907 additions and 2836 deletions

34
.github/workflows/build_latest.yml vendored Normal file
View 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

661
N_m3u8DL-CLI/CSChaCha20.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,80 +0,0 @@
using System.Collections.Generic;
namespace N_m3u8DL_CLI
{
/**
* https://www.cnblogs.com/linxuanchen/p/c-sharp-command-line-argument-parser.html
*/
public class CommandLineArgument
{
List<CommandLineArgument> _arguments;
int _index;
string _argumentText;
public CommandLineArgument Next
{
get
{
if (_index < _arguments.Count - 1)
{
return _arguments[_index + 1];
}
return null;
}
}
public CommandLineArgument Previous
{
get
{
if (_index > 0)
{
return _arguments[_index - 1];
}
return null;
}
}
internal CommandLineArgument(List<CommandLineArgument> args, int index, string argument)
{
_arguments = args;
_index = index;
_argumentText = argument;
}
public CommandLineArgument Take()
{
return Next;
}
public IEnumerable<CommandLineArgument> Take(int count)
{
var list = new List<CommandLineArgument>();
var parent = this;
for (int i = 0; i < count; i++)
{
var next = parent.Next;
if (next == null)
break;
list.Add(next);
parent = next;
}
return list;
}
public static implicit operator string(CommandLineArgument argument)
{
return argument._argumentText;
}
public override string ToString()
{
return _argumentText;
}
}
}

View File

@@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_CLI
{
public class CommandLineArgumentParser
{
List<CommandLineArgument> _arguments;
public static CommandLineArgumentParser Parse(string[] args)
{
return new CommandLineArgumentParser(args);
}
public CommandLineArgumentParser(string[] args)
{
_arguments = new List<CommandLineArgument>();
for (int i = 0; i < args.Length; i++)
{
_arguments.Add(new CommandLineArgument(_arguments, i, args[i]));
}
}
public CommandLineArgument Get(string argumentName)
{
return _arguments.FirstOrDefault(p => p == argumentName);
}
public bool Has(string argumentName)
{
return _arguments.Count(p => p == argumentName) > 0;
}
}
}

View File

@@ -0,0 +1,83 @@
using NiL.JS.BaseLibrary;
using NiL.JS.Core;
using NiL.JS.Extensions;
using System;
using Array = System.Array;
namespace N_m3u8DL_CLI
{
internal class DecodeCdeledu
{
private static string JS = @"
var _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var removePaddingChars = function(input) {
var lkey = _keyStr.indexOf(input.charAt(input.length - 1));
if (lkey == 64) {
return input.substring(0, input.length - 1);
}
return input;
}
var base64Decode = function(input, arrayBuffer) {
input = removePaddingChars(input);
input = removePaddingChars(input);
var bytes = parseInt((input.length / 4) * 3, 10);
var uarray;
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
var j = 0;
if (arrayBuffer) {
uarray = new Uint8Array(arrayBuffer);
} else {
uarray = new Uint8Array(bytes);
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, '');
for (i = 0; i < bytes; i += 3) {
enc1 = _keyStr.indexOf(input.charAt(j++));
enc2 = _keyStr.indexOf(input.charAt(j++));
enc3 = _keyStr.indexOf(input.charAt(j++));
enc4 = _keyStr.indexOf(input.charAt(j++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
uarray[i] = chr1;
if (enc3 != 64)
uarray[i + 1] = chr2;
if (enc4 != 64)
uarray[i + 2] = chr3;
}
return uarray;
}
var uint8ArrayToString = function(uDataArr) {
var arrStr = '';
for (var i = 0; i < uDataArr.length; i++) {
arrStr += String.fromCharCode(uDataArr[i]);
}
return arrStr;
}
var decodeKey = function(dataKeyString) {
var decodeArr = base64Decode(dataKeyString);
var decodeArrString = uint8ArrayToString(decodeArr);
return decodeArrString;
if (decodeArrString.indexOf('|&|') > 0) {
return decodeArrString;
}
return '';
}
";
//https://video.cdeledu.com/js/lib/cdel.hls.min-1.0.js?v=1.3
public static string DecodeKey(string txt)
{
var context = new Context();
context.Eval(JS);
var concatFunction = context.GetVariable("decodeKey").As<Function>();
string key = concatFunction.Call(new Arguments { txt }).ToString();
string realKey = key.Split(new string[] { "|&|" }, StringSplitOptions.None)[1];
return realKey;
}
}
}

View 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);
}
}
}

View File

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

View File

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

View File

@@ -1,16 +1,14 @@
using System;
using System.Collections.Generic;
using CSChaCha20;
using System;
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 +23,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,13 +40,47 @@ 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[] CHACHA20Decrypt(byte[] encryptedBuff, byte[] keyBytes, byte[] nonceBytes)
{
if (keyBytes.Length != 32)
throw new Exception("Key must be 32 bytes!");
if (nonceBytes.Length != 12 && nonceBytes.Length != 8)
throw new Exception("Key must be 12 or 8 bytes!");
if (nonceBytes.Length == 8)
nonceBytes = (new byte[4] { 0, 0, 0, 0 }).Concat(nonceBytes).ToArray();
var decStream = new MemoryStream();
using (BinaryReader reader = new BinaryReader(new MemoryStream(encryptedBuff)))
{
using (BinaryWriter writer = new BinaryWriter(decStream))
{
while (true)
{
var buffer = reader.ReadBytes(1024);
byte[] dec = new byte[buffer.Length];
if (buffer.Length > 0)
{
ChaCha20 forDecrypting = new ChaCha20(keyBytes, nonceBytes, 0);
forDecrypting.DecryptBytes(dec, buffer);
writer.Write(dec, 0, dec.Length);
}
else
{
break;
}
}
}
}
return decStream.ToArray();
}
public static byte[] HexStringToBytes(string hexStr)
{
if (string.IsNullOrEmpty(hexStr))
@@ -56,7 +88,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

View File

@@ -47,6 +47,10 @@ namespace N_m3u8DL_CLI
public long ExpectByte { get => expectByte; set => expectByte = value; }
public long StartByte { get => startByte; set => startByte = value; }
public double SegDur { get => segDur; set => segDur = value; }
public static bool EnableChaCha20 { get; set; } = false;
public static string ChaCha20KeyBase64 { get; set; }
public static string ChaCha20NonceBase64 { get; set; }
//重写WebClinet
//private class WebClient : System.Net.WebClient
@@ -179,9 +183,18 @@ namespace N_m3u8DL_CLI
if (File.Exists(savePath) && Global.ShouldStop == false)
{
FileInfo fi = new FileInfo(savePath);
if (Method == "NONE" || method.Contains("NOTSUPPORTED"))
if (File.Exists(fi.FullName) && EnableChaCha20)
{
fi.MoveTo(Path.GetDirectoryName(savePath) + "\\" + Path.GetFileNameWithoutExtension(savePath) + ".ts");
byte[] decryptBuff = Decrypter.CHACHA20Decrypt(File.ReadAllBytes(fi.FullName), Convert.FromBase64String(ChaCha20KeyBase64), Convert.FromBase64String(ChaCha20NonceBase64));
FileStream fs = new FileStream(Path.GetDirectoryName(SavePath) + "\\" + Path.GetFileNameWithoutExtension(SavePath) + ".ts", FileMode.Create);
fs.Write(decryptBuff, 0, decryptBuff.Length);
fs.Close();
DownloadManager.DownloadedSize += fi.Length;
fi.Delete();
}
else if (Method == "NONE" || Method.Contains("NOTSUPPORTED"))
{
fi.MoveTo(Path.GetDirectoryName(SavePath) + "\\" + Path.GetFileNameWithoutExtension(SavePath) + ".ts");
DownloadManager.DownloadedSize += fi.Length;
//Console.WriteLine(Path.GetFileNameWithoutExtension(savePath) + " Completed.");
}
@@ -249,4 +262,4 @@ namespace N_m3u8DL_CLI
}
}
}
}
}

View File

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

View File

@@ -62,6 +62,7 @@ namespace N_m3u8DL_CLI
targetduration = initJson["m3u8Info"]["targetDuration"].Value<double>();
TotalDuration = initJson["m3u8Info"]["totalDuration"].Value<double>();
timer.Interval = (TotalDuration - targetduration) * 1000;//设置定时器运行间隔
if (timer.Interval <= 1000) timer.Interval = 10000;
JArray lastSegments = JArray.Parse(initJson["m3u8Info"]["segments"][0].ToString().Trim()); //上次的分段,用于比对新分段
ArrayList tempList = new ArrayList(); //所有待下载的列表
tempList.Clear();
@@ -127,6 +128,7 @@ namespace N_m3u8DL_CLI
sd.Iv = info["iv"].Value<string>();
}
sd.TimeOut = (int)timer.Interval - 1000;//超时时间不超过下次执行时间
if (sd.TimeOut <= 0) sd.TimeOut = (int)timer.Interval;
sd.SegIndex = index;
sd.Headers = Headers;
sd.SegDur = info["duration"].Value<double>();

View File

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

View File

@@ -11,8 +11,6 @@ namespace N_m3u8DL_CLI
{
class LOGGER
{
public static int CursorIndex = 5;
public static int FFmpegCorsorIndex = 5;
public const int Default = 1;
public const int Error = 2;
public const int Warning = 3;
@@ -36,8 +34,13 @@ namespace N_m3u8DL_CLI
{
if (!Directory.Exists(Path.GetDirectoryName(LOGFILE)))//若文件夹不存在则新建文件夹
Directory.CreateDirectory(Path.GetDirectoryName(LOGFILE)); //新建文件夹
if (File.Exists(LOGFILE))//若文件存在则删除
File.Delete(LOGFILE);
//若文件存在则加序号
int index = 1;
var fileName = Path.GetFileNameWithoutExtension(LOGFILE);
while (File.Exists(LOGFILE))
{
LOGFILE = Path.Combine(Path.GetDirectoryName(LOGFILE), $"{fileName}-{index++}.log");
}
string file = LOGFILE;
string now = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
string init = "LOG " + DateTime.Now.ToString("yyyy/MM/dd") + "\r\n"
@@ -57,40 +60,37 @@ 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)
{
int windowWith = 63;
try
{
if (CursorIndex > 1000)
{
Console.Clear();
CursorIndex = 0;
}
if (cursorIndex == 0)
Console.SetCursorPosition(0, CursorIndex++);
else
Console.SetCursorPosition(0, cursorIndex);
windowWith = Console.WindowWidth;
}
catch (Exception)
catch (Exception e)
{
;
// empty
}
switch (printLevel)
{
case 0:
Console.Write("\r" + new string(' ', windowWith - 1) + "\r");
Console.WriteLine(" ".PadRight(12) + " " + text);
break;
case 1:
Console.Write("\r" + new string(' ', windowWith - 1) + "\r");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
Console.WriteLine(text);
break;
case 2:
Console.Write("\r" + new string(' ', windowWith - 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(' ', windowWith - 1) + "\r");
Console.Write(DateTime.Now.ToString("HH:mm:ss.fff") + " ");
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine(text);
@@ -118,7 +118,7 @@ namespace N_m3u8DL_CLI
}
catch (Exception)
{
}
finally
{
@@ -143,7 +143,7 @@ namespace N_m3u8DL_CLI
}
catch (Exception)
{
}
finally
{
@@ -156,7 +156,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();
}
}

867
N_m3u8DL-CLI/MPDParser.cs Normal file

File diff suppressed because it is too large Load Diff

110
N_m3u8DL-CLI/MyOptions.cs Normal file
View File

@@ -0,0 +1,110 @@
using CommandLine;
using CommandLine.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_CLI
{
internal class MyOptions
{
[Value(0, Hidden = true, MetaName = "Input Source", HelpText = "Help_input", ResourceType = typeof(strings))]
public string Input { get; set; }
[Option("workDir", HelpText = "Help_workDir", ResourceType = typeof(strings))]
public string WorkDir { get; set; }
[Option("saveName", HelpText = "Help_saveName", ResourceType = typeof(strings))]
public string SaveName { get; set; } = "";
[Option("baseUrl", HelpText = "Help_baseUrl", ResourceType = typeof(strings))]
public string BaseUrl { get; set; }
[Option("headers", HelpText = "Help_headers", ResourceType = typeof(strings))]
public string Headers { get; set; } = "";
[Option("maxThreads", Default = 32U, HelpText = "Help_maxThreads", ResourceType = typeof(strings))]
public uint MaxThreads { get; set; }
[Option("minThreads", Default = 16U, HelpText = "Help_minThreads", ResourceType = typeof(strings))]
public uint MinThreads { get; set; }
[Option("retryCount", Default = 15U, HelpText = "Help_retryCount", ResourceType = typeof(strings))]
public uint RetryCount { get; set; }
[Option("timeOut", Default = 10U, HelpText = "Help_timeOut", ResourceType = typeof(strings))]
public uint TimeOut { get; set; }
[Option("muxSetJson", HelpText = "Help_muxSetJson", ResourceType = typeof(strings))]
public string MuxSetJson { get; set; }
[Option("useKeyFile", HelpText = "Help_useKeyFile", ResourceType = typeof(strings))]
public string UseKeyFile { get; set; }
[Option("useKeyBase64", HelpText = "Help_useKeyBase64", ResourceType = typeof(strings))]
public string UseKeyBase64 { get; set; }
[Option("useKeyIV", HelpText = "Help_useKeyIV", ResourceType = typeof(strings))]
public string UseKeyIV { get; set; }
[Option("downloadRange", HelpText = "Help_downloadRange", ResourceType = typeof(strings))]
public string DownloadRange { get; set; }
[Option("liveRecDur", HelpText = "Help_liveRecDur", ResourceType = typeof(strings))]
public string LiveRecDur { get; set; }
[Option("stopSpeed", HelpText = "Help_stopSpeed", ResourceType = typeof(strings))]
public long StopSpeed { get; set; } = 0L;
[Option("maxSpeed", HelpText = "Help_maxSpeed", ResourceType = typeof(strings))]
public long MaxSpeed { get; set; } = 0L;
[Option("proxyAddress", HelpText = "Help_proxyAddress", ResourceType = typeof(strings))]
public string ProxyAddress { get; set; }
[Option("enableDelAfterDone", HelpText = "Help_enableDelAfterDone", ResourceType = typeof(strings))]
public bool EnableDelAfterDone { get; set; }
[Option("enableMuxFastStart", HelpText = "Help_enableMuxFastStart", ResourceType = typeof(strings))]
public bool EnableMuxFastStart { get; set; }
[Option("enableBinaryMerge", HelpText = "Help_enableBinaryMerge", ResourceType = typeof(strings))]
public bool EnableBinaryMerge { get; set; }
[Option("enableParseOnly", HelpText = "Help_enableParseOnly", ResourceType = typeof(strings))]
public bool EnableParseOnly { get; set; }
[Option("enableAudioOnly", HelpText = "Help_enableAudioOnly", ResourceType = typeof(strings))]
public bool EnableAudioOnly { get; set; }
[Option("disableDateInfo", HelpText = "Help_disableDateInfo", ResourceType = typeof(strings))]
public bool DisableDateInfo { get; set; }
[Option("disableIntegrityCheck", HelpText = "Help_disableIntegrityCheck", ResourceType = typeof(strings))]
public bool DisableIntegrityCheck { get; set; }
[Option("noMerge", HelpText = "Help_noMerge", ResourceType = typeof(strings))]
public bool NoMerge { get; set; }
[Option("noProxy", HelpText = "Help_noProxy", ResourceType = typeof(strings))]
public bool NoProxy { get; set; }
[Option("registerUrlProtocol", HelpText = "Help_registerUrlProtocol", ResourceType = typeof(strings))]
public bool RegisterUrlProtocol { get; set; }
[Option("unregisterUrlProtocol", HelpText = "Help_unregisterUrlProtocol", ResourceType = typeof(strings))]
public bool UnregisterUrlProtocol { get; set; }
[Option("enableChaCha20", HelpText = "enableChaCha20")]
public bool EnableChaCha20 { get; set; }
[Option("chaCha20KeyBase64", HelpText = "ChaCha20KeyBase64")]
public string ChaCha20KeyBase64 { get; set; }
[Option("chaCha20NonceBase64", HelpText = "ChaCha20NonceBase64")]
public string ChaCha20NonceBase64 { get; set; }
}
}

View File

@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props" Condition="Exists('..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" />
<Import Project="..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props" Condition="Exists('..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +14,8 @@
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
@@ -38,42 +42,91 @@
<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="CommandLine, Version=2.8.0.0, Culture=neutral, PublicKeyToken=5a870481e358d379, processorArchitecture=MSIL">
<HintPath>..\packages\CommandLineParser.2.8.0\lib\net45\CommandLine.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="Microsoft.Win32.TaskScheduler, Version=2.8.7.0, Culture=neutral, PublicKeyToken=c416bc1b32d97233, processorArchitecture=MSIL">
<HintPath>..\packages\TaskScheduler.2.8.7\lib\net452\Microsoft.Win32.TaskScheduler.dll</HintPath>
</Reference>
<Reference Include="MihaZupan.HttpToSocks5Proxy, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\HttpToSocks5Proxy.1.4.0\lib\net45\MihaZupan.HttpToSocks5Proxy.dll</HintPath>
</Reference>
<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=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\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.Drawing" />
<Reference Include="System.IO" />
<Reference Include="System.IO.Compression" />
<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.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="UACHelper, Version=1.3.0.4, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\UACHelper.1.3.0.5\lib\net40\UACHelper.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CommandLineArgument.cs" />
<Compile Include="CommandLineArgumentParser.cs" />
<Compile Include="CSChaCha20.cs" />
<Compile Include="Decode51CtoKey.cs" />
<Compile Include="DecodeCdeledu.cs" />
<Compile Include="DecodeDdyun.cs" />
<Compile Include="DecodeHuke88Key.cs" />
<Compile Include="DecodeImooc.cs" />
<Compile Include="Decrypter.cs" />
<Compile Include="DecodeNfmovies.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="MyOptions.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 +135,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 +150,30 @@
<Content Include="logo_3Iv_icon.ico" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<EmbeddedResource Include="strings.en-US.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>strings.en-US.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="strings.en-US.resx" />
<EmbeddedResource Include="strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>strings.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="strings.zh-TW.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>strings.zh-TW.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="strings.zh-TW.resx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Resource.Embedder.2.1.1\build\Resource.Embedder.props'))" />
<Error Condition="!Exists('..\packages\Fody.6.0.0\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.6.0.0\build\Fody.targets'))" />
<Error Condition="!Exists('..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.4.1.0\build\Costura.Fody.props'))" />
</Target>
<Import Project="..\packages\Fody.6.0.0\build\Fody.targets" Condition="Exists('..\packages\Fody.6.0.0\build\Fody.targets')" />
</Project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
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)
{
int windowWith = 63;
try
{
windowWith = Console.WindowWidth;
}
catch (Exception e)
{
// empty
}
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 = windowWith - 4 - ProgressReporter.progress.Length - ProgressReporter.speed.Length - now.Length;
if (sub <= 0) sub = 0;
string print = now + " " + ProgressReporter.progress + " " + ProgressReporter.speed + new string(' ', sub);
Console.Write("\r" + print + "\r");
//Console.Write(print);
}
}
}
}

View File

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("nilaoda")]
[assembly: AssemblyProduct("N_m3u8DL-CLI")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyCopyright("Copyright © 2022")]
[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("3.0.2.0")]
[assembly: AssemblyFileVersion("3.0.2.0")]

View File

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

362
N_m3u8DL-CLI/changelog.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BrotliSharpLib" version="0.3.3" targetFramework="net46" />
<package id="CommandLineParser" version="2.8.0" 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="HttpToSocks5Proxy" version="1.4.0" targetFramework="net46" />
<package id="Newtonsoft.Json" version="13.0.1" 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" />
<package id="TaskScheduler" version="2.8.7" targetFramework="net46" />
<package id="UACHelper" version="1.3.0.5" targetFramework="net46" />
</packages>

File diff suppressed because it is too large Load Diff

View File

@@ -183,34 +183,6 @@
<data name="hasExternalSubtitleTrack" xml:space="preserve">
<value>Has External Subtitle Track</value>
</data>
<data name="helpInfo" xml:space="preserve">
<value>N_m3u8DL-CLI.exe &lt;URL|JSON|FILE&gt; [OPTIONS]
--workDir Directory Set work dir (Video will be here)
--saveName Filename Set save name(Exclude extention)
--baseUrl BaseUrl Set Baseurl
--headers headers Set HTTP headersformat: key:value user | split all key&amp;value
--maxThreads Thread Set max thread(default: 32)
--minThreads Thread Set min thread(default: 16)
--retryCount Count Set retry times(default: 15)
--timeOut Sec Set timeout for http request(seconddefault: 10)
--muxSetJson File Set a json file for mux
--useKeyFile File Use 16 bytes file as KEY for AES-128 decryption
--useKeyBase64 Base64String Use Base64 String as KEY for AES-128 decryption
--useKeyIV HEXString Use HEX String as IV for AES-128 decryption
--downloadRange Range Set range for a video
--stopSpeed Number Speed below this, retry(KB/s)
--maxSpeed Number Set max download speed(KB/s)
--enableDelAfterDone Enable delete clips after download completed
--enableMuxFastStart Enable fast start for mp4
--enableBinaryMerge Enable use binary merge instead ffmpeg
--enableParseOnly Enable parse mode
--enableAudioOnly Enable only audio track when mux use ffmpeg
--disableDateInfo Disable write date info when mux use ffmpeg
--noMerge Disable auto merge
--noProxy Disable use system proxy
--disableIntegrityCheck Disable integrity check</value>
</data>
<data name="invalidM3u8" xml:space="preserve">
<value>Invalid M3u8 (NOT Contain #EXTM3U)</value>
</data>
@@ -298,4 +270,109 @@
<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>
<data name="Help_workDir" xml:space="preserve">
<value>Set work dir (Video will be here)</value>
</data>
<data name="Help_saveName" xml:space="preserve">
<value>Set save name(Exclude extention)</value>
</data>
<data name="Help_input" xml:space="preserve">
<value>URL|File|JSON</value>
</data>
<data name="Help_baseUrl" xml:space="preserve">
<value>Set Baseurl</value>
</data>
<data name="Help_headers" xml:space="preserve">
<value>Set HTTP headersformat: key:value use | split all key&amp;value</value>
</data>
<data name="Help_maxThreads" xml:space="preserve">
<value>Set max thread</value>
</data>
<data name="Help_minThreads" xml:space="preserve">
<value>Set min thread</value>
</data>
<data name="Help_retryCount" xml:space="preserve">
<value>Set retry times</value>
</data>
<data name="Help_timeOut" xml:space="preserve">
<value>Set timeout for http request(second)</value>
</data>
<data name="Help_muxSetJson" xml:space="preserve">
<value>Set a json file for mux</value>
</data>
<data name="Help_useKeyFile" xml:space="preserve">
<value>Use 16 bytes file as KEY for AES-128 decryption</value>
</data>
<data name="Help_useKeyBase64" xml:space="preserve">
<value>Use Base64 String as KEY for AES-128 decryption</value>
</data>
<data name="Help_useKeyIV" xml:space="preserve">
<value>Use HEX String as IV for AES-128 decryption</value>
</data>
<data name="Help_downloadRange" xml:space="preserve">
<value>Set range for a video</value>
</data>
<data name="Help_liveRecDur" xml:space="preserve">
<value>When the live recording reaches this length, the software will exit automatically(HH:MM:SS)</value>
</data>
<data name="Help_stopSpeed" xml:space="preserve">
<value>Speed below this, retry(KB/s)</value>
</data>
<data name="Help_maxSpeed" xml:space="preserve">
<value>Set max download speed(KB/s)</value>
</data>
<data name="Help_proxyAddress" xml:space="preserve">
<value>Set HTTP/SOCKS5 Proxy, like http://127.0.0.1:8080</value>
</data>
<data name="Help_enableDelAfterDone" xml:space="preserve">
<value>Enable delete clips after download completed</value>
</data>
<data name="Help_enableMuxFastStart" xml:space="preserve">
<value>Enable fast start for mp4</value>
</data>
<data name="Help_enableBinaryMerge" xml:space="preserve">
<value>Enable use binary merge instead of ffmpeg</value>
</data>
<data name="Help_enableParseOnly" xml:space="preserve">
<value>Enable parse only mode</value>
</data>
<data name="Help_enableAudioOnly" xml:space="preserve">
<value>Enable only audio track when mux use ffmpeg</value>
</data>
<data name="Help_disableDateInfo" xml:space="preserve">
<value>Disable write date info when mux use ffmpeg</value>
</data>
<data name="Help_noMerge" xml:space="preserve">
<value>Disable auto merge</value>
</data>
<data name="Help_noProxy" xml:space="preserve">
<value>Disable use system proxy</value>
</data>
<data name="Help_disableIntegrityCheck" xml:space="preserve">
<value>Disable integrity check</value>
</data>
<data name="Help_registerUrlProtocol" xml:space="preserve">
<value>Register m3u8dl URL protocol</value>
</data>
<data name="Help_unregisterUrlProtocol" xml:space="preserve">
<value>Unregister m3u8dl URL protocol</value>
</data>
<data name="registerUrlProtocolFailed" xml:space="preserve">
<value>Register m3u8dl URL protocol failed!</value>
</data>
<data name="registerUrlProtocolSuccessful" xml:space="preserve">
<value>Register m3u8dl URL protocol successfully!</value>
</data>
<data name="unregisterUrlProtocolFailed" xml:space="preserve">
<value>Unregister m3u8dl URL protocol failed!</value>
</data>
<data name="unregisterUrlProtocolSuccessful" xml:space="preserve">
<value>Unregister m3u8dl URL protocol successfully!</value>
</data>
</root>

View File

@@ -183,35 +183,6 @@
<data name="hasExternalSubtitleTrack" xml:space="preserve">
<value>识别到外挂字幕轨道</value>
</data>
<data name="helpInfo" xml:space="preserve">
<value>N_m3u8DL-CLI.exe &lt;URL|File|JSON&gt; [OPTIONS]
--workDir Directory 设定程序工作目录
--saveName Filename 设定存储文件名(不包括后缀)
--baseUrl BaseUrl 设定Baseurl
--headers headers 设定请求头,格式 key:value 使用|分割不同的key&amp;value
--maxThreads Thread 设定程序的最大线程数(默认为32)
--minThreads Thread 设定程序的最小线程数(默认为16)
--retryCount Count 设定程序的重试次数(默认为15)
--timeOut Sec 设定程序网络请求的超时时间(单位为秒默认为10秒)
--muxSetJson File 使用外部json文件定义混流选项
--useKeyFile File 使用外部16字节文件定义AES-128解密KEY
--useKeyBase64 Base64String 使用Base64字符串定义AES-128解密KEY
--useKeyIV HEXString 使用HEX字符串定义AES-128解密IV
--downloadRange Range 仅下载视频的一部分分片或长度
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
--maxSpeed Number 设置下载速度上限(单位为KB/s)
--enableDelAfterDone 开启下载后删除临时文件夹的功能
--enableMuxFastStart 开启混流mp4的FastStart特性
--enableBinaryMerge 开启二进制合并分片
--enableParseOnly 开启仅解析模式(程序只进行到meta.json)
--enableAudioOnly 合并时仅封装音频轨道
--disableDateInfo 关闭混流中的日期写入
--noMerge 禁用自动合并
--noProxy 不自动使用系统代理
--disableIntegrityCheck 不检测分片数量是否完整</value>
</data>
<data name="invalidM3u8" xml:space="preserve">
<value>无效的m3u8</value>
</data>
@@ -299,4 +270,109 @@
<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>
<data name="Help_workDir" xml:space="preserve">
<value>设定程序工作目录</value>
</data>
<data name="Help_saveName" xml:space="preserve">
<value>设定存储文件名(不包括后缀)</value>
</data>
<data name="Help_input" xml:space="preserve">
<value>链接或文件</value>
</data>
<data name="Help_baseUrl" xml:space="preserve">
<value>设定Baseurl</value>
</data>
<data name="Help_headers" xml:space="preserve">
<value>设定请求头,格式 key:value 使用|分割不同的key&amp;value</value>
</data>
<data name="Help_maxThreads" xml:space="preserve">
<value>设定程序的最大线程数</value>
</data>
<data name="Help_minThreads" xml:space="preserve">
<value>设定程序的最小线程数</value>
</data>
<data name="Help_retryCount" xml:space="preserve">
<value>设定程序的重试次数</value>
</data>
<data name="Help_timeOut" xml:space="preserve">
<value>设定程序网络请求的超时时间(单位为秒)</value>
</data>
<data name="Help_muxSetJson" xml:space="preserve">
<value>使用外部json文件定义混流选项</value>
</data>
<data name="Help_useKeyFile" xml:space="preserve">
<value>使用外部16字节文件定义AES-128解密KEY</value>
</data>
<data name="Help_useKeyBase64" xml:space="preserve">
<value>使用Base64字符串定义AES-128解密KEY</value>
</data>
<data name="Help_useKeyIV" xml:space="preserve">
<value>使用HEX字符串定义AES-128解密IV</value>
</data>
<data name="Help_downloadRange" xml:space="preserve">
<value>仅下载视频的一部分分片或长度</value>
</data>
<data name="Help_liveRecDur" xml:space="preserve">
<value>直播录制时,达到此长度自动退出软件(HH:MM:SS)</value>
</data>
<data name="Help_stopSpeed" xml:space="preserve">
<value>当速度低于此值时,重试(单位为KB/s)</value>
</data>
<data name="Help_maxSpeed" xml:space="preserve">
<value>设置下载速度上限(单位为KB/s)</value>
</data>
<data name="Help_proxyAddress" xml:space="preserve">
<value>设置HTTP/SOCKS5代理, 如 http://127.0.0.1:8080</value>
</data>
<data name="Help_enableDelAfterDone" xml:space="preserve">
<value>开启下载后删除临时文件夹的功能</value>
</data>
<data name="Help_enableMuxFastStart" xml:space="preserve">
<value>开启混流mp4的FastStart特性</value>
</data>
<data name="Help_enableBinaryMerge" xml:space="preserve">
<value>开启二进制合并分片</value>
</data>
<data name="Help_enableParseOnly" xml:space="preserve">
<value>开启仅解析模式(程序只进行到meta.json)</value>
</data>
<data name="Help_enableAudioOnly" xml:space="preserve">
<value>合并时仅封装音频轨道</value>
</data>
<data name="Help_disableDateInfo" xml:space="preserve">
<value>关闭混流中的日期写入</value>
</data>
<data name="Help_noMerge" xml:space="preserve">
<value>禁用自动合并</value>
</data>
<data name="Help_noProxy" xml:space="preserve">
<value>不自动使用系统代理</value>
</data>
<data name="Help_disableIntegrityCheck" xml:space="preserve">
<value>不检测分片数量是否完整</value>
</data>
<data name="Help_registerUrlProtocol" xml:space="preserve">
<value>注册m3u8dl链接协议</value>
</data>
<data name="Help_unregisterUrlProtocol" xml:space="preserve">
<value>取消注册m3u8dl链接协议</value>
</data>
<data name="registerUrlProtocolFailed" xml:space="preserve">
<value>注册m3u8dl链接协议失败</value>
</data>
<data name="registerUrlProtocolSuccessful" xml:space="preserve">
<value>注册m3u8dl链接协议成功</value>
</data>
<data name="unregisterUrlProtocolFailed" xml:space="preserve">
<value>取消注册m3u8dl链接协议失败</value>
</data>
<data name="unregisterUrlProtocolSuccessful" xml:space="preserve">
<value>取消注册m3u8dl链接协议成功</value>
</data>
</root>

View File

@@ -183,35 +183,6 @@
<data name="hasExternalSubtitleTrack" xml:space="preserve">
<value>識別到外掛字幕軌道</value>
</data>
<data name="helpInfo" xml:space="preserve">
<value>N_m3u8DL-CLI.exe &lt;URL|File|JSON&gt; [OPTIONS]
--workDir Directory 設定程序工作目錄
--saveName Filename 設定存儲文件名(不包括後綴)
--baseUrl BaseUrl 設定Baseurl
--headers headers 設定請求頭,格式 key:value 使用|分割不同的key&amp;value
--maxThreads Thread 設定程序的最大線程數(默認為32)
--minThreads Thread 設定程序的最小線程數(默認為16)
--retryCount Count 設定程序的重試次數(默認為15)
--timeOut Sec 設定程序網絡請求的超時時間(單位為秒默認為10秒)
--muxSetJson File 使用外部json文件定義混流選項
--useKeyFile File 使用外部16字節文件定義AES-128解密KEY
--useKeyBase64 Base64String 使用Base64字符串定義AES-128解密KEY
--useKeyIV HEXString 使用HEX字符串定義AES-128解密IV
--downloadRange Range 僅下載視頻的壹部分分片或長度
--liveRecDur HH:MM:SS 直播錄制時,達到此長度自動退出軟件
--stopSpeed Number 當速度低於此值時,重試(單位為KB/s)
--maxSpeed Number 設置下載速度上限(單位為KB/s)
--enableDelAfterDone 開啟下載後刪除臨時文件夾的功能
--enableMuxFastStart 開啟混流mp4的FastStart特性
--enableBinaryMerge 開啟二進制合並分片
--enableParseOnly 開啟僅解析模式(程序只進行到meta.json)
--enableAudioOnly 合並時僅封裝音頻軌道
--disableDateInfo 關閉混流中的日期寫入
--noMerge 禁用自動合並
--noProxy 不自動使用系統代理
--disableIntegrityCheck 不檢測分片數量是否完整</value>
</data>
<data name="invalidM3u8" xml:space="preserve">
<value>無效的m3u8</value>
</data>
@@ -299,4 +270,109 @@
<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>
<data name="Help_workDir" xml:space="preserve">
<value>設定程式工作目錄</value>
</data>
<data name="Help_saveName" xml:space="preserve">
<value>設定存儲文件名(不包括後綴)</value>
</data>
<data name="Help_input" xml:space="preserve">
<value>連結或檔案</value>
</data>
<data name="Help_baseUrl" xml:space="preserve">
<value>設定Baseurl</value>
</data>
<data name="Help_headers" xml:space="preserve">
<value>設定請求頭,格式 key:value 使用|分割不同的key&amp;value</value>
</data>
<data name="Help_maxThreads" xml:space="preserve">
<value>設定程式的最大線程數</value>
</data>
<data name="Help_minThreads" xml:space="preserve">
<value>設定程式的最小線程數</value>
</data>
<data name="Help_retryCount" xml:space="preserve">
<value>設定程式的重試次數</value>
</data>
<data name="Help_timeOut" xml:space="preserve">
<value>設定程式網絡請求的超時時間(單位為秒)</value>
</data>
<data name="Help_muxSetJson" xml:space="preserve">
<value>使用外部json文件定義混流選項</value>
</data>
<data name="Help_useKeyFile" xml:space="preserve">
<value>使用外部16字節文件定義AES-128解密KEY</value>
</data>
<data name="Help_useKeyBase64" xml:space="preserve">
<value>使用Base64字符串定義AES-128解密KEY</value>
</data>
<data name="Help_useKeyIV" xml:space="preserve">
<value>使用HEX字符串定義AES-128解密IV</value>
</data>
<data name="Help_downloadRange" xml:space="preserve">
<value>僅下載視頻的壹部分分片或長度</value>
</data>
<data name="Help_liveRecDur" xml:space="preserve">
<value>直播錄制時,達到此長度自動退出軟件(HH:MM:SS)</value>
</data>
<data name="Help_stopSpeed" xml:space="preserve">
<value>當速度低於此值時,重試(單位為KB/s)</value>
</data>
<data name="Help_maxSpeed" xml:space="preserve">
<value>設置下載速度上限(單位為KB/s)</value>
</data>
<data name="Help_proxyAddress" xml:space="preserve">
<value>設置HTTP/SOCKS5代理, 如 http://127.0.0.1:8080</value>
</data>
<data name="Help_enableDelAfterDone" xml:space="preserve">
<value>開啟下載後刪除臨時文件夾的功能</value>
</data>
<data name="Help_enableMuxFastStart" xml:space="preserve">
<value>開啟混流mp4的FastStart特性</value>
</data>
<data name="Help_enableBinaryMerge" xml:space="preserve">
<value>開啟二進制合並分片</value>
</data>
<data name="Help_enableParseOnly" xml:space="preserve">
<value>開啟僅解析模式(程式只進行到meta.json)</value>
</data>
<data name="Help_enableAudioOnly" xml:space="preserve">
<value>合並時僅封裝音頻軌道</value>
</data>
<data name="Help_disableDateInfo" xml:space="preserve">
<value>關閉混流中的日期寫入</value>
</data>
<data name="Help_noMerge" xml:space="preserve">
<value>禁用自動合並</value>
</data>
<data name="Help_noProxy" xml:space="preserve">
<value>不自動使用系統代理</value>
</data>
<data name="Help_disableIntegrityCheck" xml:space="preserve">
<value>不檢測分片數量是否完整</value>
</data>
<data name="Help_registerUrlProtocol" xml:space="preserve">
<value>注册m3u8dl連結協定</value>
</data>
<data name="Help_unregisterUrlProtocol" xml:space="preserve">
<value>取消注册m3u8dl連結協定</value>
</data>
<data name="registerUrlProtocolFailed" xml:space="preserve">
<value>注册m3u8dl連結協定失敗</value>
</data>
<data name="registerUrlProtocolSuccessful" xml:space="preserve">
<value>注册m3u8dl連結協定成功</value>
</data>
<data name="unregisterUrlProtocolFailed" xml:space="preserve">
<value>取消注册m3u8dl連結協定失敗</value>
</data>
<data name="unregisterUrlProtocolSuccessful" xml:space="preserve">
<value>取消注册m3u8dl連結協定成功</value>
</data>
</root>

108
README.md
View File

@@ -13,20 +13,23 @@
# [ENGLISH VERSION](https://github.com/nilaoda/N_m3u8DL-CLI/blob/master/README_ENG.md)
# 下载使用
* 发行版: https://github.com/nilaoda/N_m3u8DL-CLI/releases
* 自动构建版`(供测试)`: https://github.com/nilaoda/N_m3u8DL-CLI/actions
# 关于开源
本项目已2019年10月9日开源采用MIT许可证各取所需。
本项目已2019年10月9日开源采用MIT许可证各取所需。
# 关于跨平台
~~本项目已通过`.NET Core`实现跨平台理论支持Mac、Linux、Windows等平台请移步https://github.com/nilaoda/N_m3u8DL-CLI_Core~~
暂时放弃跨平台很多API需要重写才能实现功能日后有空再维护
未来可期
# N_m3u8DL-CLI
一个**简单易用的**m3u8下载器下载地址https://github.com/nilaoda/N_m3u8DL-CLI/releases
支持下载m3u8链接或文件为`mp4`或`ts`格式,并提供丰富的命令行选项。
* **不支持**优酷视频解密
* **不支持**气球云视频解密
* 支持`AES-128-CBC`加密自动解密
* 支持多线程下载
* 支持下载限速
@@ -39,7 +42,9 @@
* 支持下载路径为网络驱动器的情况
* 支持下载外挂字幕轨道、音频轨道
* 支持仅合并为音频
* 自动使用系统代理(可禁止)
* 支持设置特定http代理
* 支持自动使用系统代理(默认行为, 可禁止)
* 支持m3u8dl链接协议通过web链接调用本机客户端
* 提供SimpleG简易的`GUI`生成常用参数
@@ -48,37 +53,76 @@
# 命令行选项
```
N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
N_m3u8DL-CLI
--workDir Directory 设定程序工作目录
--saveName Filename 设定存储文件名(不包括后缀)
--baseUrl BaseUrl 设定Baseurl
--headers headers 设定请求头,格式 key:value 使用|分割不同的key&value
--maxThreads Thread 设定程序的最大线程数(默认为32)
--minThreads Thread 设定程序的最小线程数(默认为16)
--retryCount Count 设定程序的重试次数(默认为15)
--timeOut Sec 设定程序网络请求的超时时间(单位为秒默认为10秒)
--muxSetJson File 使用外部json文件定义混流选项
--useKeyFile File 使用外部16字节文件定义AES-128解密KEY
--useKeyBase64 Base64String 使用Base64字符串定义AES-128解密KEY
--useKeyIV HEXString 使用HEX字符串定义AES-128解密IV
--downloadRange Range 仅下载视频的一部分分片或长度
--liveRecDur HH:MM:SS 直播录制时,达到此长度自动退出软件
--stopSpeed Number 当速度低于此值时,重试(单位为KB/s)
--maxSpeed Number 设置下载速度上限(单位为KB/s)
--enableDelAfterDone 开启下载后删除临时文件夹的功能
--enableMuxFastStart 开启混流mp4的FastStart特性
--enableBinaryMerge 开启二进制合并分片
--enableParseOnly 开启仅解析模式(程序只进行到meta.json)
--enableAudioOnly 合并时仅封装音频轨道
--disableDateInfo 关闭混流中的日期写入
--noMerge 禁用自动合并
--noProxy 不自动使用系统代理
--disableIntegrityCheck 不检测分片数量是否完整
USAGE:
N_m3u8DL-CLI <URL|JSON|FILE> [OPTIONS]
OPTIONS:
--workDir 设定程序工作目录
--saveName 设定存储文件名(不包括后缀)
--baseUrl 设定Baseurl
--headers 设定请求头,格式 key:value 使用|分割不同的key&value
--maxThreads (Default: 32) 设定程序的最大线程数
--minThreads (Default: 16) 设定程序的最小线程数
--retryCount (Default: 15) 设定程序的重试次数
--timeOut (Default: 10) 设定程序网络请求的超时时间(单位为秒)
--muxSetJson 使用外部json文件定义混流选项
--useKeyFile 使用外部16字节文件定义AES-128解密KEY
--useKeyBase64 使用Base64字符串定义AES-128解密KEY
--useKeyIV 使用HEX字符串定义AES-128解密IV
--downloadRange 仅下载视频的一部分分片或长度
--liveRecDur 直播录制时,达到此长度自动退出软件(HH:MM:SS)
--stopSpeed 当速度低于此值时,重试(单位为KB/s)
--maxSpeed 设置下载速度上限(单位为KB/s)
--proxyAddress 设置HTTP/SOCKS5代理, 如 http://127.0.0.1:8080
--enableDelAfterDone 开启下载后删除临时文件夹的功能
--enableMuxFastStart 开启混流mp4的FastStart特性
--enableBinaryMerge 开启二进制合并分片
--enableParseOnly 开启仅解析模式(程序只进行到meta.json)
--enableAudioOnly 合并时仅封装音频轨道
--disableDateInfo 关闭混流中的日期写入
--disableIntegrityCheck 不检测分片数量是否完整
--noMerge 禁用自动合并
--noProxy 不自动使用系统代理
--registerUrlProtocol 注册m3u8dl链接协议
--unregisterUrlProtocol 取消注册m3u8dl链接协议
--enableChaCha20 enableChaCha20
--chaCha20KeyBase64 ChaCha20KeyBase64
--chaCha20NonceBase64 ChaCha20NonceBase64
--help Display this help screen.
--version Display version information.
```
# 关于`m3u8dl://`协议
新增命令行参数:
```
--registerUrlProtocol 注册m3u8dl链接协议
--unregisterUrlProtocol 取消注册m3u8dl链接协议
```
URI格式
```
m3u8dl://<base64编码的客户端命令行文本>
```
URI示例
```
m3u8dl://Imh0dHBzOi8vZXhhbXBsZS5jb20vYWJjLm0zdTgiIC0td29ya0RpciAiJVVTRVJQUk9GSUxFJVxEb3dubG9hZHNcbTN1OGRsIiAtLXNhdmVOYW1lICJhYmMiIC0tZW5hYmxlRGVsQWZ0ZXJEb25lIC0tZGlzYWJsZURhdGVJbmZvIC0tbm9Qcm94eQ==
```
URI解码结果
```
"https://example.com/abc.m3u8" --workDir "%USERPROFILE%\Downloads\m3u8dl" --saveName "abc" --enableDelAfterDone --disableDateInfo --noProxy
```
# 用户文档
https://nilaoda.github.io/N_m3u8DL-CLI/
# 聊聊
https://discord.gg/W5tvcRJDPs
# 赞赏
https://nilaoda.github.io/N_m3u8DL-CLI/source/images/alipay.png
![Wow](https://nilaoda.github.io/N_m3u8DL-CLI/source/images/alipay.png)

View File

@@ -8,10 +8,10 @@
╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚════╝ ╚═════╝ ╚══════╝ ╚═════╝╚══════╝╚═╝
```
This is a m3u8 downloader.
This is an m3u8 downloader.
## Summary
Supports:
* Auto deceypt for `AES-128-CBC`
* Auto decrypt for `AES-128-CBC`
* `Master List`
* Live stream recording(`BETA`)
* Customize HTTP headers
@@ -20,8 +20,8 @@ Supports:
* Network driver on Windows OS
* Alternative audio/video track
* Mux without video track
* Auto use system proxy
* Optimization for Chinese streaming platform
* Custom HTTP proxy or Use system proxy
* Optimization for Chinese streaming platforms
![ScreenShot](https://nilaoda.github.io/N_m3u8DL-CLI/source/images/%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8.gif)
@@ -30,33 +30,75 @@ Supports:
## Options
```
N_m3u8DL-CLI.exe <URL|JSON|FILE> [OPTIONS]
N_m3u8DL-CLI
--workDir Directory Set work dir (Video will be here)
--saveName Filename Set save name(Exclude extention)
--baseUrl BaseUrl Set Baseurl
--headers headers Set HTTP headersformat: key:value user | split all key&value
--maxThreads Thread Set max thread(default: 32)
--minThreads Thread Set min thread(default: 16)
--retryCount Count Set retry times(default: 15)
--timeOut Sec Set timeout for http request(seconddefault: 10)
--muxSetJson File Set a json file for mux
--useKeyFile File Use 16 bytes file as KEY for AES-128 decryption
--useKeyBase64 Base64String Use Base64 String as KEY for AES-128 decryption
--useKeyIV HEXString Use HEX String as IV for AES-128 decryption
--downloadRange Range Set range for a video
--stopSpeed Number Speed below this, retry(KB/s)
--maxSpeed Number Set max download speed(KB/s)
--enableDelAfterDone Enable delete clips after download completed
--enableMuxFastStart Enable fast start for mp4
--enableBinaryMerge Enable use binary merge instead ffmpeg
--enableParseOnly Enable parse mode
--enableAudioOnly Enable only audio track when mux use ffmpeg
--disableDateInfo Disable write date info when mux use ffmpeg
--noMerge Disable auto merge
--noProxy Disable use system proxy
--disableIntegrityCheck Disable integrity check
USAGE:
N_m3u8DL-CLI <URL|JSON|FILE> [OPTIONS]
OPTIONS:
--workDir Set work dir (Video will be here)
--saveName Set save name(Exclude extention)
--baseUrl Set Baseurl
--headers Set HTTP headersformat: key:value use | split all
key&value
--maxThreads (Default: 32) Set max thread
--minThreads (Default: 16) Set min thread
--retryCount (Default: 15) Set retry times
--timeOut (Default: 10) Set timeout for http request(second)
--muxSetJson Set a json file for mux
--useKeyFile Use 16 bytes file as KEY for AES-128 decryption
--useKeyBase64 Use Base64 String as KEY for AES-128 decryption
--useKeyIV Use HEX String as IV for AES-128 decryption
--downloadRange Set range for a video
--liveRecDur When the live recording reaches this length, the
software will exit automatically(HH:MM:SS)
--stopSpeed Speed below this, retry(KB/s)
--maxSpeed Set max download speed(KB/s)
--proxyAddress Set HTTP/SOCKS5 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 of ffmpeg
--enableParseOnly Enable parse only mode
--enableAudioOnly Enable only audio track when mux use ffmpeg
--disableDateInfo Disable write date info when mux use ffmpeg
--disableIntegrityCheck Disable integrity check
--noMerge Disable auto merge
--noProxy Disable use system proxy
--registerUrlProtocol Register m3u8dl URL protocol
--unregisterUrlProtocol Unregister m3u8dl URL protocol
--enableChaCha20 enableChaCha20
--chaCha20KeyBase64 ChaCha20KeyBase64
--chaCha20NonceBase64 ChaCha20NonceBase64
--help Display this help screen.
--version Display version information.
```
## About `m3u8dl://`
New commandline options
```
--registerUrlProtocol Register m3u8dl URL protocol
--unregisterUrlProtocol Unregister m3u8dl URL protocol
```
URI Format
```
m3u8dl://<base64 encoded params>
```
URI Example
```
m3u8dl://Imh0dHBzOi8vZXhhbXBsZS5jb20vYWJjLm0zdTgiIC0td29ya0RpciAiJVVTRVJQUk9GSUxFJVxEb3dubG9hZHNcbTN1OGRsIiAtLXNhdmVOYW1lICJhYmMiIC0tZW5hYmxlRGVsQWZ0ZXJEb25lIC0tZGlzYWJsZURhdGVJbmZvIC0tbm9Qcm94eQ==
```
URI Decode Result
```
"https://example.com/abc.m3u8" --workDir "%USERPROFILE%\Downloads\m3u8dl" --saveName "abc" --enableDelAfterDone --disableDateInfo --noProxy
```
## Document
https://nilaoda.github.io/N_m3u8DL-CLI/
https://nilaoda.github.io/N_m3u8DL-CLI/
## Chit-chat
https://discord.gg/W5tvcRJDPs

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