支持从音频修正VTT字幕时间轴
This commit is contained in:
parent
f873cbc2dd
commit
3b7d32077e
|
@ -16,6 +16,7 @@ namespace N_m3u8DL_RE.Common
|
|||
[JsonSerializable(typeof(IOrderedEnumerable<StreamSpec>))]
|
||||
[JsonSerializable(typeof(IEnumerable<MediaSegment>))]
|
||||
[JsonSerializable(typeof(List<StreamSpec>))]
|
||||
[JsonSerializable(typeof(List<MediaSegment>))]
|
||||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||
internal partial class JsonContext : JsonSerializerContext { }
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
public static string cmd_liveRecordLimit { get => GetText("cmd_liveRecordLimit"); }
|
||||
public static string cmd_taskStartAt { get => GetText("cmd_taskStartAt"); }
|
||||
public static string cmd_liveWaitTime { get => GetText("cmd_liveWaitTime"); }
|
||||
public static string cmd_liveFixVttByAudio { get => GetText("cmd_liveFixVttByAudio"); }
|
||||
public static string cmd_liveRealTimeMerge { get => GetText("cmd_liveRealTimeMerge"); }
|
||||
public static string cmd_livePerformAsVod { get => GetText("cmd_livePerformAsVod"); }
|
||||
public static string cmd_muxAfterDone { get => GetText("cmd_muxAfterDone"); }
|
||||
|
|
|
@ -154,6 +154,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
|||
zhTW: "mkvmerge可執行程序全路徑, 例如 C:\\Tools\\mkvmerge.exe",
|
||||
enUS: "Full path to the mkvmerge binary, like C:\\Tools\\mkvmerge.exe"
|
||||
),
|
||||
["cmd_liveFixVttByAudio"] = new TextContainer
|
||||
(
|
||||
zhCN: "通过读取音频文件的起始时间修正VTT字幕",
|
||||
zhTW: "透過讀取音訊檔案的起始時間修正VTT字幕",
|
||||
enUS: "Correct VTT sub by reading the start time of the audio file"
|
||||
),
|
||||
["cmd_header"] = new TextContainer
|
||||
(
|
||||
zhCN: "为HTTP请求设置特定的请求头, 例如:\r\n-H \"Cookie: mycookie\" -H \"User-Agent: iOS\"",
|
||||
|
|
|
@ -79,6 +79,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
private readonly static Option<bool> LivePipeMux = new(new string[] { "--live-pipe-mux" }, description: ResString.cmd_livePipeMux, getDefaultValue: () => false);
|
||||
private readonly static Option<TimeSpan?> LiveRecordLimit = new(new string[] { "--live-record-limit" }, description: ResString.cmd_liveRecordLimit, parseArgument: ParseLiveLimit) { ArgumentHelpName = "HH:mm:ss" };
|
||||
private readonly static Option<int?> LiveWaitTime = new(new string[] { "--live-wait-time" }, description: ResString.cmd_liveWaitTime) { ArgumentHelpName = "SEC" };
|
||||
private readonly static Option<bool> LiveFixVttByAudio = new(new string[] { "--live-fix-vtt-by-audio" }, description: ResString.cmd_liveFixVttByAudio, getDefaultValue: () => false);
|
||||
|
||||
|
||||
//复杂命令行如下
|
||||
|
@ -418,6 +419,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
TaskStartAt = bindingContext.ParseResult.GetValueForOption(TaskStartAt),
|
||||
LivePerformAsVod = bindingContext.ParseResult.GetValueForOption(LivePerformAsVod),
|
||||
LivePipeMux = bindingContext.ParseResult.GetValueForOption(LivePipeMux),
|
||||
LiveFixVttByAudio = bindingContext.ParseResult.GetValueForOption(LiveFixVttByAudio),
|
||||
UseSystemProxy = bindingContext.ParseResult.GetValueForOption(UseSystemProxy),
|
||||
CustomProxy = bindingContext.ParseResult.GetValueForOption(CustomProxy),
|
||||
LiveWaitTime = bindingContext.ParseResult.GetValueForOption(LiveWaitTime),
|
||||
|
@ -487,7 +489,7 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
||||
MuxAfterDone,
|
||||
CustomHLSMethod, CustomHLSKey, CustomHLSIv, UseSystemProxy, CustomProxy, TaskStartAt,
|
||||
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LivePipeMux, LiveRecordLimit, LiveWaitTime,
|
||||
LivePerformAsVod, LiveRealTimeMerge, LiveKeepSegments, LivePipeMux, LiveFixVttByAudio, LiveRecordLimit, LiveWaitTime,
|
||||
MuxImports, VideoFilter, AudioFilter, SubtitleFilter, DropVideoFilter, DropAudioFilter, DropSubtitleFilter, MoreHelp
|
||||
};
|
||||
|
||||
|
|
|
@ -226,5 +226,9 @@ namespace N_m3u8DL_RE.CommandLine
|
|||
/// See: <see cref="CommandInvoker.LivePipeMux"/>.
|
||||
/// </summary>
|
||||
public bool LivePipeMux { get; set; }
|
||||
/// <summary>
|
||||
/// See: <see cref="CommandInvoker.LiveFixVttByAudio"/>.
|
||||
/// </summary>
|
||||
public bool LiveFixVttByAudio { get; set; }
|
||||
}
|
||||
}
|
|
@ -45,6 +45,9 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
ConcurrentDictionary<int, long> DateTimeDic = new(); //上次下载的dateTime
|
||||
CancellationTokenSource CancellationTokenSource = new(); //取消Wait
|
||||
|
||||
private readonly object lockObj = new object();
|
||||
TimeSpan? audioStart = null;
|
||||
|
||||
public SimpleLiveRecordManager2(DownloaderConfig downloaderConfig, List<StreamSpec> selectedSteams, StreamExtractor streamExtractor)
|
||||
{
|
||||
this.DownloaderConfig = downloaderConfig;
|
||||
|
@ -248,6 +251,10 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
Logger.WarnMarkUp(ResString.readingInfo);
|
||||
mediaInfos = await MediainfoUtil.ReadInfoAsync(DownloaderConfig.MyOptions.FFmpegBinaryPath!, result.ActualFilePath);
|
||||
mediaInfos.ForEach(info => Logger.InfoMarkUp(info.ToStringMarkUp()));
|
||||
lock (lockObj)
|
||||
{
|
||||
if (audioStart == null) audioStart = mediaInfos.FirstOrDefault(x => x.Type == "Audio")?.StartTime;
|
||||
}
|
||||
ChangeSpecInfo(streamSpec, mediaInfos, ref useAACFilter);
|
||||
readInfo = true;
|
||||
}
|
||||
|
@ -324,6 +331,10 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
Logger.WarnMarkUp(ResString.readingInfo);
|
||||
mediaInfos = await MediainfoUtil.ReadInfoAsync(DownloaderConfig.MyOptions.FFmpegBinaryPath!, result!.ActualFilePath);
|
||||
mediaInfos.ForEach(info => Logger.InfoMarkUp(info.ToStringMarkUp()));
|
||||
lock (lockObj)
|
||||
{
|
||||
if (audioStart == null) audioStart = mediaInfos.FirstOrDefault(x => x.Type == "Audio")?.StartTime;
|
||||
}
|
||||
ChangeSpecInfo(streamSpec, mediaInfos, ref useAACFilter);
|
||||
readInfo = true;
|
||||
}
|
||||
|
@ -367,7 +378,13 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
foreach (var seg in keys)
|
||||
{
|
||||
var vttContent = File.ReadAllText(FileDic[seg]!.ActualFilePath);
|
||||
var vtt = WebVttSub.Parse(vttContent);
|
||||
var waitCount = 0;
|
||||
while (DownloaderConfig.MyOptions.LiveFixVttByAudio && audioStart == null && waitCount++ < 5)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
var subOffset = audioStart != null ? (long)audioStart.Value.TotalMilliseconds : 0L;
|
||||
var vtt = WebVttSub.Parse(vttContent, subOffset);
|
||||
//手动计算MPEGTS
|
||||
if (currentVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||
{
|
||||
|
@ -773,6 +790,11 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
if (WAIT_SEC <= 0) WAIT_SEC = 1;
|
||||
Logger.WarnMarkUp($"set refresh interval to {WAIT_SEC} seconds");
|
||||
}
|
||||
//如果没有选中音频 取消通过音频修复vtt时间轴
|
||||
if (!SelectedSteams.Any(x => x.MediaType == MediaType.AUDIO))
|
||||
{
|
||||
DownloaderConfig.MyOptions.LiveFixVttByAudio = false;
|
||||
}
|
||||
|
||||
/*//写出master
|
||||
if (DownloaderConfig.MyOptions.LiveWriteHLS)
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace N_m3u8DL_RE.Entity
|
|||
public string? Resolution { get; set; }
|
||||
public string? Fps { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public TimeSpan? StartTime { get; set; }
|
||||
public bool DolbyVison { get; set; }
|
||||
public bool HDR { get; set; }
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>0.1.5.3</Version>
|
||||
<Version>0.1.5.4</Version>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace N_m3u8DL_RE.Util
|
|||
private static partial Regex FpsRegex();
|
||||
[GeneratedRegex("DOVI configuration record.*profile: (\\d).*compatibility id: (\\d)")]
|
||||
private static partial Regex DoViRegex();
|
||||
[GeneratedRegex("Duration.*?start: (\\d+\\.?\\d{0,3})")]
|
||||
private static partial Regex StartRegex();
|
||||
|
||||
public static async Task<List<Mediainfo>> ReadInfoAsync(string binary, string file)
|
||||
{
|
||||
|
@ -73,6 +75,13 @@ namespace N_m3u8DL_RE.Util
|
|||
)
|
||||
info.DolbyVison = true;
|
||||
|
||||
if (StartRegex().IsMatch(output))
|
||||
{
|
||||
var f = StartRegex().Match(output).Groups[1].Value;
|
||||
if (double.TryParse(f, out var d))
|
||||
info.StartTime = TimeSpan.FromSeconds(d);
|
||||
}
|
||||
|
||||
result.Add(info);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue