使用ffmpeg读取媒体信息以辅助判断媒体类型
This commit is contained in:
parent
9be32b2872
commit
df354e4eb8
|
@ -69,6 +69,24 @@ namespace N_m3u8DL_RE.Common.Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Dolby Vision content is detected, binary merging is automatically enabled 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string autoBinaryMerge2 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("autoBinaryMerge2", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 An unrecognized encryption method is detected, binary merging is automatically enabled 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string autoBinaryMerge3 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("autoBinaryMerge3", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Bad m3u8 的本地化字符串。
|
/// 查找类似 Bad m3u8 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -368,6 +386,15 @@ namespace N_m3u8DL_RE.Common.Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 ffmpeg not found, please download at: https://ffmpeg.org/download.html 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string ffmpegNotFound {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ffmpegNotFound", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Extracting TTML(raw) subtitle... 的本地化字符串。
|
/// 查找类似 Extracting TTML(raw) subtitle... 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -503,6 +530,15 @@ namespace N_m3u8DL_RE.Common.Resource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Reading media info... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string readingInfo {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("readingInfo", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Trying to search for KEY from text file... 的本地化字符串。
|
/// 查找类似 Trying to search for KEY from text file... 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -264,4 +264,16 @@
|
||||||
<data name="searchKey" xml:space="preserve">
|
<data name="searchKey" xml:space="preserve">
|
||||||
<value>Trying to search for KEY from text file...</value>
|
<value>Trying to search for KEY from text file...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ffmpegNotFound" xml:space="preserve">
|
||||||
|
<value>ffmpeg not found, please download at: https://ffmpeg.org/download.html</value>
|
||||||
|
</data>
|
||||||
|
<data name="readingInfo" xml:space="preserve">
|
||||||
|
<value>Reading media info...</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge2" xml:space="preserve">
|
||||||
|
<value>Dolby Vision content is detected, binary merging is automatically enabled</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge3" xml:space="preserve">
|
||||||
|
<value>An unrecognized encryption method is detected, binary merging is automatically enabled</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -284,4 +284,16 @@
|
||||||
<data name="searchKey" xml:space="preserve">
|
<data name="searchKey" xml:space="preserve">
|
||||||
<value>正在尝试从文本文件搜索KEY...</value>
|
<value>正在尝试从文本文件搜索KEY...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ffmpegNotFound" xml:space="preserve">
|
||||||
|
<value>找不到ffmpeg,请自行下载:https://ffmpeg.org/download.html</value>
|
||||||
|
</data>
|
||||||
|
<data name="readingInfo" xml:space="preserve">
|
||||||
|
<value>读取媒体信息...</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge2" xml:space="preserve">
|
||||||
|
<value>检测到杜比视界内容,自动开启二进制合并</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge3" xml:space="preserve">
|
||||||
|
<value>检测到无法识别的加密方式,自动开启二进制合并</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -261,4 +261,16 @@
|
||||||
<data name="searchKey" xml:space="preserve">
|
<data name="searchKey" xml:space="preserve">
|
||||||
<value>正在嘗試從文本文件搜尋KEY...</value>
|
<value>正在嘗試從文本文件搜尋KEY...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ffmpegNotFound" xml:space="preserve">
|
||||||
|
<value>找不到ffmpeg,請自行下載:https://ffmpeg.org/download.html</value>
|
||||||
|
</data>
|
||||||
|
<data name="readingInfo" xml:space="preserve">
|
||||||
|
<value>讀取媒體訊息...</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge2" xml:space="preserve">
|
||||||
|
<value>檢測到杜比視界內容,自動開啟二進位制合併</value>
|
||||||
|
</data>
|
||||||
|
<data name="autoBinaryMerge3" xml:space="preserve">
|
||||||
|
<value>檢測到無法識別的加密方式,自動開啟二進位制合併</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -57,7 +57,7 @@ namespace N_m3u8DL_RE.Parser.Processor.HLS
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ResString.cmd_loadKeyFailed + ": " + ex.ToString());
|
Logger.Error(ResString.cmd_loadKeyFailed + ": " + ex.Message);
|
||||||
encryptInfo.Method = EncryptMethod.UNKNOWN;
|
encryptInfo.Method = EncryptMethod.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,17 +26,37 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
NowDateTime = DateTime.Now;
|
NowDateTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask task)
|
private string? ReadInit(byte[] data)
|
||||||
{
|
{
|
||||||
string? ReadInit(byte[] data)
|
var info = MP4InitUtil.ReadInit(data);
|
||||||
|
if (info.Scheme != null) Logger.WarnMarkUp($"[grey]Type: {info.Scheme}[/]");
|
||||||
|
if (info.PSSH != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {info.PSSH}[/]");
|
||||||
|
if (info.KID != null) Logger.WarnMarkUp($"[grey]KID: {info.KID}[/]");
|
||||||
|
return info.KID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChangeSpecInfo(StreamSpec streamSpec, List<Mediainfo> mediainfos)
|
||||||
|
{
|
||||||
|
if (!DownloaderConfig.BinaryMerge && mediainfos.Any(m => m.DolbyVison == true))
|
||||||
{
|
{
|
||||||
var info = MP4InitUtil.ReadInit(data);
|
DownloaderConfig.BinaryMerge = true;
|
||||||
if (info.Scheme != null) Logger.WarnMarkUp($"[grey]Type: {info.Scheme}[/]");
|
Logger.WarnMarkUp(ResString.autoBinaryMerge2);
|
||||||
if (info.PSSH != null) Logger.WarnMarkUp($"[grey]PSSH(WV): {info.PSSH}[/]");
|
|
||||||
if (info.KID != null) Logger.WarnMarkUp($"[grey]KID: {info.KID}[/]");
|
|
||||||
return info.KID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mediainfos.All(m => m.Type == "Audio"))
|
||||||
|
{
|
||||||
|
streamSpec.MediaType = MediaType.AUDIO;
|
||||||
|
}
|
||||||
|
else if (mediainfos.All(m => m.Type == "Subtitle"))
|
||||||
|
{
|
||||||
|
streamSpec.MediaType = MediaType.SUBTITLES;
|
||||||
|
if (streamSpec.Extension == null || streamSpec.Extension == "ts")
|
||||||
|
streamSpec.Extension = "vtt";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask task)
|
||||||
|
{
|
||||||
ConcurrentDictionary<MediaSegment, DownloadResult?> FileDic = new();
|
ConcurrentDictionary<MediaSegment, DownloadResult?> FileDic = new();
|
||||||
|
|
||||||
var segments = streamSpec.Playlist?.MediaParts.SelectMany(m => m.MediaSegments);
|
var segments = streamSpec.Playlist?.MediaParts.SelectMany(m => m.MediaSegments);
|
||||||
|
@ -50,19 +70,14 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
var saveDir = DownloaderConfig.SaveDir ?? Environment.CurrentDirectory;
|
var saveDir = DownloaderConfig.SaveDir ?? Environment.CurrentDirectory;
|
||||||
var saveName = DownloaderConfig.SaveName != null ? $"{DownloaderConfig.SaveName}.{type}.{streamSpec.Language}".TrimEnd('.') : dirName;
|
var saveName = DownloaderConfig.SaveName != null ? $"{DownloaderConfig.SaveName}.{type}.{streamSpec.Language}".TrimEnd('.') : dirName;
|
||||||
var headers = DownloaderConfig.Headers;
|
var headers = DownloaderConfig.Headers;
|
||||||
var output = Path.Combine(saveDir, saveName + $".{streamSpec.Extension ?? "ts"}");
|
|
||||||
//检测目标文件是否存在
|
|
||||||
while (File.Exists(output))
|
|
||||||
{
|
|
||||||
Logger.WarnMarkUp($"{output} => {output = Path.ChangeExtension(output, $"copy" + Path.GetExtension(output))}");
|
|
||||||
}
|
|
||||||
|
|
||||||
//mp4decrypt
|
//mp4decrypt
|
||||||
var mp4decrypt = DownloaderConfig.DecryptionBinaryPath!;
|
var mp4decrypt = DownloaderConfig.DecryptionBinaryPath!;
|
||||||
var mp4InitFile = "";
|
var mp4InitFile = "";
|
||||||
var currentKID = "";
|
var currentKID = "";
|
||||||
|
var readInfo = false; //是否读取过
|
||||||
|
|
||||||
Logger.Debug($"dirName: {dirName}; tmpDir: {tmpDir}; saveDir: {saveDir}; saveName: {saveName}; output: {output}");
|
Logger.Debug($"dirName: {dirName}; tmpDir: {tmpDir}; saveDir: {saveDir}; saveName: {saveName}");
|
||||||
|
|
||||||
//创建文件夹
|
//创建文件夹
|
||||||
if (!Directory.Exists(tmpDir)) Directory.CreateDirectory(tmpDir);
|
if (!Directory.Exists(tmpDir)) Directory.CreateDirectory(tmpDir);
|
||||||
|
@ -83,7 +98,13 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
//下载init
|
//下载init
|
||||||
if (streamSpec.Playlist?.MediaInit != null)
|
if (streamSpec.Playlist?.MediaInit != null)
|
||||||
{
|
{
|
||||||
totalCount++;
|
//对于fMP4,自动开启二进制合并
|
||||||
|
if (!DownloaderConfig.BinaryMerge && streamSpec.MediaType != MediaType.SUBTITLES)
|
||||||
|
{
|
||||||
|
DownloaderConfig.BinaryMerge = true;
|
||||||
|
Logger.WarnMarkUp($"[darkorange3_1]{ResString.autoBinaryMerge}[/]");
|
||||||
|
}
|
||||||
|
|
||||||
var path = Path.Combine(tmpDir, "_init.mp4.tmp");
|
var path = Path.Combine(tmpDir, "_init.mp4.tmp");
|
||||||
var result = await Downloader.DownloadSegmentAsync(streamSpec.Playlist.MediaInit, path, headers);
|
var result = await Downloader.DownloadSegmentAsync(streamSpec.Playlist.MediaInit, path, headers);
|
||||||
FileDic[streamSpec.Playlist.MediaInit] = result;
|
FileDic[streamSpec.Playlist.MediaInit] = result;
|
||||||
|
@ -94,12 +115,6 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
mp4InitFile = result.ActualFilePath;
|
mp4InitFile = result.ActualFilePath;
|
||||||
task.Increment(1);
|
task.Increment(1);
|
||||||
|
|
||||||
//修改输出后缀
|
|
||||||
if (streamSpec.MediaType == Common.Enum.MediaType.AUDIO)
|
|
||||||
output = Path.ChangeExtension(output, ".m4a");
|
|
||||||
else
|
|
||||||
output = Path.ChangeExtension(output, ".mp4");
|
|
||||||
|
|
||||||
//读取mp4信息
|
//读取mp4信息
|
||||||
if (result != null && result.Success)
|
if (result != null && result.Success)
|
||||||
{
|
{
|
||||||
|
@ -125,11 +140,53 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
FileDic[streamSpec.Playlist.MediaInit]!.ActualFilePath = dec;
|
FileDic[streamSpec.Playlist.MediaInit]!.ActualFilePath = dec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//ffmpeg读取信息
|
||||||
|
if (!readInfo)
|
||||||
|
{
|
||||||
|
Logger.WarnMarkUp(ResString.readingInfo);
|
||||||
|
var mediainfos = await MediainfoUtil.ReadInfoAsync(DownloaderConfig.FFmpegBinaryPath!, result.ActualFilePath);
|
||||||
|
mediainfos.ForEach(info => Logger.InfoMarkUp(info.ToStringMarkUp()));
|
||||||
|
ChangeSpecInfo(streamSpec, mediainfos);
|
||||||
|
readInfo = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//开始下载
|
//计算填零个数
|
||||||
var pad = "0".PadLeft(segments.Count().ToString().Length, '0');
|
var pad = "0".PadLeft(segments.Count().ToString().Length, '0');
|
||||||
|
|
||||||
|
//下载第一个分片
|
||||||
|
if (!readInfo)
|
||||||
|
{
|
||||||
|
var seg = segments.First();
|
||||||
|
segments = segments.Skip(1);
|
||||||
|
|
||||||
|
var index = seg.Index;
|
||||||
|
var path = Path.Combine(tmpDir, index.ToString(pad) + $".{streamSpec.Extension ?? "clip"}.tmp");
|
||||||
|
var result = await Downloader.DownloadSegmentAsync(seg, path, headers);
|
||||||
|
FileDic[seg] = result;
|
||||||
|
task.Increment(1);
|
||||||
|
//实时解密
|
||||||
|
if (DownloaderConfig.MP4RealTimeDecryption && seg.EncryptInfo.Method != Common.Enum.EncryptMethod.NONE && result != null)
|
||||||
|
{
|
||||||
|
var enc = result.ActualFilePath;
|
||||||
|
var dec = Path.Combine(Path.GetDirectoryName(enc)!, Path.GetFileNameWithoutExtension(enc) + "_dec" + Path.GetExtension(enc));
|
||||||
|
var dResult = await MP4DecryptUtil.DecryptAsync(DownloaderConfig.UseShakaPackager, mp4decrypt, DownloaderConfig.Keys, enc, dec, currentKID, mp4InitFile);
|
||||||
|
if (dResult)
|
||||||
|
{
|
||||||
|
File.Delete(enc);
|
||||||
|
result.ActualFilePath = dec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//ffmpeg读取信息
|
||||||
|
Logger.WarnMarkUp(ResString.readingInfo);
|
||||||
|
var mediainfos = await MediainfoUtil.ReadInfoAsync(DownloaderConfig.FFmpegBinaryPath!, result!.ActualFilePath);
|
||||||
|
mediainfos.ForEach(info => Logger.InfoMarkUp(info.ToStringMarkUp()));
|
||||||
|
ChangeSpecInfo(streamSpec, mediainfos);
|
||||||
|
readInfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//开始下载
|
||||||
var options = new ParallelOptions()
|
var options = new ParallelOptions()
|
||||||
{
|
{
|
||||||
MaxDegreeOfParallelism = DownloaderConfig.ThreadCount
|
MaxDegreeOfParallelism = DownloaderConfig.ThreadCount
|
||||||
|
@ -155,6 +212,19 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var output = Path.Combine(saveDir, saveName + $".{streamSpec.Extension ?? "ts"}");
|
||||||
|
//检测目标文件是否存在
|
||||||
|
while (File.Exists(output))
|
||||||
|
{
|
||||||
|
Logger.WarnMarkUp($"{output} => {output = Path.ChangeExtension(output, $"copy" + Path.GetExtension(output))}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//修改输出后缀
|
||||||
|
if (streamSpec.MediaType == Common.Enum.MediaType.AUDIO)
|
||||||
|
output = Path.ChangeExtension(output, ".m4a");
|
||||||
|
else if (streamSpec.MediaType != Common.Enum.MediaType.SUBTITLES)
|
||||||
|
output = Path.ChangeExtension(output, ".mp4");
|
||||||
|
|
||||||
if (DownloaderConfig.MP4RealTimeDecryption && mp4InitFile != "")
|
if (DownloaderConfig.MP4RealTimeDecryption && mp4InitFile != "")
|
||||||
{
|
{
|
||||||
File.Delete(mp4InitFile);
|
File.Delete(mp4InitFile);
|
||||||
|
@ -346,13 +416,6 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
//合并
|
//合并
|
||||||
if (!DownloaderConfig.SkipMerge)
|
if (!DownloaderConfig.SkipMerge)
|
||||||
{
|
{
|
||||||
//对于fMP4,自动开启二进制合并
|
|
||||||
if (!DownloaderConfig.BinaryMerge && streamSpec.MediaType != MediaType.SUBTITLES && mp4InitFile != "")
|
|
||||||
{
|
|
||||||
DownloaderConfig.BinaryMerge = true;
|
|
||||||
Logger.WarnMarkUp($"[white on darkorange3_1]{ResString.autoBinaryMerge}[/]");
|
|
||||||
}
|
|
||||||
|
|
||||||
//字幕也使用二进制合并
|
//字幕也使用二进制合并
|
||||||
if (DownloaderConfig.BinaryMerge || streamSpec.MediaType == MediaType.SUBTITLES)
|
if (DownloaderConfig.BinaryMerge || streamSpec.MediaType == MediaType.SUBTITLES)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace N_m3u8DL_RE.Downloader
|
||||||
}
|
}
|
||||||
else if (segment.EncryptInfo.Method == EncryptMethod.SAMPLE_AES_CTR)
|
else if (segment.EncryptInfo.Method == EncryptMethod.SAMPLE_AES_CTR)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("SAMPLE-AES-CTR");
|
//throw new NotSupportedException("SAMPLE-AES-CTR");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dResult;
|
return dResult;
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace N_m3u8DL_RE.Entity
|
||||||
|
{
|
||||||
|
internal class Mediainfo
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Text { get; set; }
|
||||||
|
public string BaseInfo { get; set; }
|
||||||
|
public string Bitrate { get; set; }
|
||||||
|
public string Resolution { get; set; }
|
||||||
|
public string Fps { get; set; }
|
||||||
|
public string Type { get; set; }
|
||||||
|
public bool DolbyVison { get; set; }
|
||||||
|
|
||||||
|
public override string? ToString()
|
||||||
|
{
|
||||||
|
return $"{(string.IsNullOrEmpty(Id) ? "NaN" : Id)}: " + string.Join(", ", new List<string> { Type, BaseInfo, Resolution, Fps, Bitrate }.Where(i => !string.IsNullOrEmpty(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToStringMarkUp()
|
||||||
|
{
|
||||||
|
return "[steelblue]" + ToString().EscapeMarkup() + (DolbyVison ? " [darkorange3_1][[DOVI]][/]" : "") + "[/]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,13 +39,12 @@ namespace N_m3u8DL_RE
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//预先检查ffmpeg
|
//预先检查ffmpeg
|
||||||
if (!option.BinaryMerge)
|
if (option.FFmpegBinaryPath == null)
|
||||||
{
|
|
||||||
option.FFmpegBinaryPath = GlobalUtil.FindExecutable("ffmpeg");
|
option.FFmpegBinaryPath = GlobalUtil.FindExecutable("ffmpeg");
|
||||||
if (string.IsNullOrEmpty(option.FFmpegBinaryPath))
|
|
||||||
{
|
if (string.IsNullOrEmpty(option.FFmpegBinaryPath))
|
||||||
throw new FileNotFoundException("ffmpeg not found!");
|
{
|
||||||
}
|
throw new FileNotFoundException(ResString.ffmpegNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
//预先检查
|
//预先检查
|
||||||
|
@ -192,6 +191,12 @@ namespace N_m3u8DL_RE
|
||||||
if (lists.Count() > 1)
|
if (lists.Count() > 1)
|
||||||
await extractor.FetchPlayListAsync(selectedStreams);
|
await extractor.FetchPlayListAsync(selectedStreams);
|
||||||
|
|
||||||
|
//无法识别的加密方式,自动开启二进制合并
|
||||||
|
if (selectedStreams.Any(s => s.Playlist.MediaParts.Any(p => p.MediaSegments.Any(m => m.EncryptInfo.Method == EncryptMethod.UNKNOWN))))
|
||||||
|
{
|
||||||
|
Logger.WarnMarkUp($"[darkorange3_1]{ResString.autoBinaryMerge3}[/]");
|
||||||
|
}
|
||||||
|
|
||||||
if (option.WriteMetaJson)
|
if (option.WriteMetaJson)
|
||||||
{
|
{
|
||||||
Logger.Warn(ResString.writeJson);
|
Logger.Warn(ResString.writeJson);
|
||||||
|
@ -228,7 +233,11 @@ namespace N_m3u8DL_RE
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex.ToString());
|
string msg = ex.Message;
|
||||||
|
#if DEBUG
|
||||||
|
msg = ex.ToString();
|
||||||
|
#endif
|
||||||
|
Logger.Error(msg);
|
||||||
await Task.Delay(3000);
|
await Task.Delay(3000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
using N_m3u8DL_RE.Entity;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
namespace N_m3u8DL_RE.Util
|
||||||
|
{
|
||||||
|
internal partial class MediainfoUtil
|
||||||
|
{
|
||||||
|
[RegexGenerator(" Stream #.*")]
|
||||||
|
private static partial Regex TextRegex();
|
||||||
|
[RegexGenerator("#0:\\d(\\[0x\\w+?\\])")]
|
||||||
|
private static partial Regex IdRegex();
|
||||||
|
[RegexGenerator(": (\\w+): (.*)")]
|
||||||
|
private static partial Regex TypeRegex();
|
||||||
|
[RegexGenerator("(.*?)(,|$)")]
|
||||||
|
private static partial Regex BaseInfoRegex();
|
||||||
|
[RegexGenerator(" \\/ 0x\\w+")]
|
||||||
|
private static partial Regex ReplaceRegex();
|
||||||
|
[RegexGenerator("\\d{2,}x\\d+")]
|
||||||
|
private static partial Regex ResRegex();
|
||||||
|
[RegexGenerator("\\d+ kb\\/s")]
|
||||||
|
private static partial Regex BitrateRegex();
|
||||||
|
[RegexGenerator("\\d+ fps")]
|
||||||
|
private static partial Regex FpsRegex();
|
||||||
|
|
||||||
|
public static async Task<List<Mediainfo>> ReadInfoAsync(string binary, string file)
|
||||||
|
{
|
||||||
|
var result = new List<Mediainfo>();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(file) || !File.Exists(file)) return result;
|
||||||
|
|
||||||
|
string cmd = "-hide_banner -i \"" + file + "\"";
|
||||||
|
var p = Process.Start(new ProcessStartInfo()
|
||||||
|
{
|
||||||
|
FileName = binary,
|
||||||
|
Arguments = cmd,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
UseShellExecute = false
|
||||||
|
})!;
|
||||||
|
var output = p.StandardError.ReadToEnd();
|
||||||
|
await p.WaitForExitAsync();
|
||||||
|
|
||||||
|
foreach (Match stream in TextRegex().Matches(output))
|
||||||
|
{
|
||||||
|
var info = new Mediainfo()
|
||||||
|
{
|
||||||
|
Text = TypeRegex().Match(stream.Value).Groups[2].Value,
|
||||||
|
Id = IdRegex().Match(stream.Value).Groups[1].Value,
|
||||||
|
Type = TypeRegex().Match(stream.Value).Groups[1].Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
info.Resolution = ResRegex().Match(info.Text).Value;
|
||||||
|
info.Bitrate = BitrateRegex().Match(info.Text).Value;
|
||||||
|
info.Fps = FpsRegex().Match(info.Text).Value;
|
||||||
|
info.BaseInfo = BaseInfoRegex().Match(info.Text).Groups[1].Value;
|
||||||
|
info.BaseInfo = ReplaceRegex().Replace(info.BaseInfo, "");
|
||||||
|
|
||||||
|
if (info.BaseInfo.Contains("dvhe")
|
||||||
|
|| info.BaseInfo.Contains("dvh1")
|
||||||
|
|| info.BaseInfo.Contains("DOVI")
|
||||||
|
|| info.Type.Contains("dvvideo")
|
||||||
|
)
|
||||||
|
info.DolbyVison = true;
|
||||||
|
|
||||||
|
result.Add(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Count == 0)
|
||||||
|
{
|
||||||
|
result.Add(new Mediainfo()
|
||||||
|
{
|
||||||
|
Type = "Unknown"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,6 +51,13 @@ namespace N_m3u8DL_RE.Util
|
||||||
{
|
{
|
||||||
string dateString = string.IsNullOrEmpty(recTime) ? DateTime.Now.ToString("o") : recTime;
|
string dateString = string.IsNullOrEmpty(recTime) ? DateTime.Now.ToString("o") : recTime;
|
||||||
|
|
||||||
|
//同名文件已存在的共存策略
|
||||||
|
if (File.Exists($"{outputPath}.{muxFormat.ToLower()}"))
|
||||||
|
{
|
||||||
|
outputPath = Path.Combine(Path.GetDirectoryName(outputPath)!,
|
||||||
|
Path.GetFileName(outputPath) + "_" + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
|
||||||
|
}
|
||||||
|
|
||||||
bool useAACFilter = true;
|
bool useAACFilter = true;
|
||||||
StringBuilder command = new StringBuilder("-loglevel warning -i concat:\"");
|
StringBuilder command = new StringBuilder("-loglevel warning -i concat:\"");
|
||||||
string ddpAudio = string.Empty;
|
string ddpAudio = string.Empty;
|
||||||
|
|
Loading…
Reference in New Issue