优化直播字幕时间轴处理
This commit is contained in:
parent
d96a45251b
commit
31482c8d34
|
@ -164,6 +164,11 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerable<SubCue> GetCues()
|
||||||
|
{
|
||||||
|
return this.Cues.Where(c => !string.IsNullOrEmpty(c.Payload));
|
||||||
|
}
|
||||||
|
|
||||||
private static TimeSpan ConvertToTS(string str)
|
private static TimeSpan ConvertToTS(string str)
|
||||||
{
|
{
|
||||||
var ms = Convert.ToInt32(str.Split('.').Last());
|
var ms = Convert.ToInt32(str.Split('.').Last());
|
||||||
|
@ -180,7 +185,7 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
foreach (var c in this.Cues)
|
foreach (var c in GetCues()) //输出时去除空串
|
||||||
{
|
{
|
||||||
sb.AppendLine(c.StartTime.ToString(@"hh\:mm\:ss\.fff") + " --> " + c.EndTime.ToString(@"hh\:mm\:ss\.fff") + " " + c.Settings);
|
sb.AppendLine(c.StartTime.ToString(@"hh\:mm\:ss\.fff") + " --> " + c.EndTime.ToString(@"hh\:mm\:ss\.fff") + " " + c.Settings);
|
||||||
sb.AppendLine(c.Payload);
|
sb.AppendLine(c.Payload);
|
||||||
|
@ -190,9 +195,32 @@ namespace N_m3u8DL_RE.Common.Entity
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToStringWithHeader()
|
public string ToVtt()
|
||||||
{
|
{
|
||||||
return "WEBVTT" + Environment.NewLine + Environment.NewLine + ToString();
|
return "WEBVTT" + Environment.NewLine + Environment.NewLine + ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ToSrt()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int index = 1;
|
||||||
|
foreach (var c in GetCues())
|
||||||
|
{
|
||||||
|
sb.AppendLine($"{index++}");
|
||||||
|
sb.AppendLine(c.StartTime.ToString(@"hh\:mm\:ss\,fff") + " --> " + c.EndTime.ToString(@"hh\:mm\:ss\,fff"));
|
||||||
|
sb.AppendLine(c.Payload);
|
||||||
|
sb.AppendLine();
|
||||||
|
}
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
|
var srt = sb.ToString();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(srt.Trim()))
|
||||||
|
{
|
||||||
|
srt = "1\r\n00:00:00,000 --> 00:00:01,000"; //空字幕
|
||||||
|
}
|
||||||
|
|
||||||
|
return srt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,10 +62,10 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
|
|
||||||
//选中第一个SmoothStreamingMedia节点
|
//选中第一个SmoothStreamingMedia节点
|
||||||
var ssmElement = xmlDocument.Elements().First(e => e.Name.LocalName == "SmoothStreamingMedia");
|
var ssmElement = xmlDocument.Elements().First(e => e.Name.LocalName == "SmoothStreamingMedia");
|
||||||
bool isLive = Convert.ToBoolean(ssmElement.Attribute("IsLive")?.Value ?? "FALSE");
|
|
||||||
var timeScaleStr = ssmElement.Attribute("TimeScale")?.Value ?? "10000000";
|
var timeScaleStr = ssmElement.Attribute("TimeScale")?.Value ?? "10000000";
|
||||||
var durationStr = ssmElement.Attribute("Duration")?.Value;
|
var durationStr = ssmElement.Attribute("Duration")?.Value;
|
||||||
var isLiveStr = ssmElement.Attribute("IsLive")?.Value;
|
var isLiveStr = ssmElement.Attribute("IsLive")?.Value;
|
||||||
|
bool isLive = Convert.ToBoolean(isLiveStr ?? "FALSE");
|
||||||
|
|
||||||
var isProtection = false;
|
var isProtection = false;
|
||||||
var protectionSystemId = "";
|
var protectionSystemId = "";
|
||||||
|
@ -121,6 +121,7 @@ namespace N_m3u8DL_RE.Parser.Extractor
|
||||||
var channels = qualityLevel.Attribute("Channels")?.Value;
|
var channels = qualityLevel.Attribute("Channels")?.Value;
|
||||||
|
|
||||||
StreamSpec streamSpec = new();
|
StreamSpec streamSpec = new();
|
||||||
|
streamSpec.PublishTime = DateTime.Now; //发布时间默认现在
|
||||||
streamSpec.Extension = "m4s";
|
streamSpec.Extension = "m4s";
|
||||||
streamSpec.OriginalUrl = ParserConfig.OriginalUrl;
|
streamSpec.OriginalUrl = ParserConfig.OriginalUrl;
|
||||||
streamSpec.PeriodId = indexStr;
|
streamSpec.PeriodId = indexStr;
|
||||||
|
|
|
@ -122,6 +122,11 @@ namespace Mp4SubtitleParser
|
||||||
return MultiElementsFixRegex().Matches(xml).Select(m => m.Value).ToList();
|
return MultiElementsFixRegex().Matches(xml).Select(m => m.Value).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static WebVttSub ExtractFromMp4(string item, long segTimeMs, long baseTimestamp = 0L)
|
||||||
|
{
|
||||||
|
return ExtractFromMp4s(new string[] { item }, segTimeMs, baseTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
public static WebVttSub ExtractFromMp4s(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
|
public static WebVttSub ExtractFromMp4s(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
|
||||||
{
|
{
|
||||||
//read ttmls
|
//read ttmls
|
||||||
|
@ -163,6 +168,11 @@ namespace Mp4SubtitleParser
|
||||||
return ExtractSub(xmls, baseTimestamp);
|
return ExtractSub(xmls, baseTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static WebVttSub ExtractFromTTML(string item, long segTimeMs, long baseTimestamp = 0L)
|
||||||
|
{
|
||||||
|
return ExtractFromTTMLs(new string[] { item }, segTimeMs, baseTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
public static WebVttSub ExtractFromTTMLs(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
|
public static WebVttSub ExtractFromTTMLs(IEnumerable<string> items, long segTimeMs, long baseTimestamp = 0L)
|
||||||
{
|
{
|
||||||
//read ttmls
|
//read ttmls
|
||||||
|
|
|
@ -360,12 +360,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
FileDic.Clear();
|
FileDic.Clear();
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
||||||
var subContentFixed = finalVtt.ToStringWithHeader();
|
var subContentFixed = finalVtt.ToVtt();
|
||||||
//转换字幕格式
|
//转换字幕格式
|
||||||
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
||||||
{
|
{
|
||||||
path = Path.ChangeExtension(path, ".srt");
|
path = Path.ChangeExtension(path, ".srt");
|
||||||
subContentFixed = OtherUtil.WebVtt2Other(finalVtt, DownloaderConfig.MyOptions.SubtitleFormat);
|
subContentFixed = finalVtt.ToSrt();
|
||||||
}
|
}
|
||||||
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
||||||
FileDic[keys.First()] = new DownloadResult()
|
FileDic[keys.First()] = new DownloadResult()
|
||||||
|
@ -394,12 +394,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
FileDic.Clear();
|
FileDic.Clear();
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
||||||
var subContentFixed = finalVtt.ToStringWithHeader();
|
var subContentFixed = finalVtt.ToVtt();
|
||||||
//转换字幕格式
|
//转换字幕格式
|
||||||
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
||||||
{
|
{
|
||||||
path = Path.ChangeExtension(path, ".srt");
|
path = Path.ChangeExtension(path, ".srt");
|
||||||
subContentFixed = OtherUtil.WebVtt2Other(finalVtt, DownloaderConfig.MyOptions.SubtitleFormat);
|
subContentFixed = finalVtt.ToSrt();
|
||||||
}
|
}
|
||||||
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
||||||
FileDic[firstKey] = new DownloadResult()
|
FileDic[firstKey] = new DownloadResult()
|
||||||
|
@ -420,7 +420,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
var keys = FileDic.OrderBy(s => s.Key.Index).Select(s => s.Key);
|
var keys = FileDic.OrderBy(s => s.Key.Index).Select(s => s.Key);
|
||||||
foreach (var seg in keys)
|
foreach (var seg in keys)
|
||||||
{
|
{
|
||||||
var vtt = MP4TtmlUtil.ExtractFromTTMLs(new string[] { FileDic[seg]!.ActualFilePath }, 0);
|
var vtt = MP4TtmlUtil.ExtractFromTTML(FileDic[seg]!.ActualFilePath, 0);
|
||||||
//手动计算MPEGTS
|
//手动计算MPEGTS
|
||||||
if (finalVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
if (finalVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
{
|
{
|
||||||
|
@ -452,12 +452,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
FileDic.Clear();
|
FileDic.Clear();
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
||||||
var subContentFixed = finalVtt.ToStringWithHeader();
|
var subContentFixed = finalVtt.ToVtt();
|
||||||
//转换字幕格式
|
//转换字幕格式
|
||||||
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
||||||
{
|
{
|
||||||
path = Path.ChangeExtension(path, ".srt");
|
path = Path.ChangeExtension(path, ".srt");
|
||||||
subContentFixed = OtherUtil.WebVtt2Other(finalVtt, DownloaderConfig.MyOptions.SubtitleFormat);
|
subContentFixed = finalVtt.ToSrt();
|
||||||
}
|
}
|
||||||
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
||||||
FileDic[firstKey] = new DownloadResult()
|
FileDic[firstKey] = new DownloadResult()
|
||||||
|
@ -482,7 +482,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
var keys = FileDic.OrderBy(s => s.Key.Index).Where(v => v.Value!.ActualFilePath.EndsWith(".m4s")).Select(s => s.Key);
|
var keys = FileDic.OrderBy(s => s.Key.Index).Where(v => v.Value!.ActualFilePath.EndsWith(".m4s")).Select(s => s.Key);
|
||||||
foreach (var seg in keys)
|
foreach (var seg in keys)
|
||||||
{
|
{
|
||||||
var vtt = MP4TtmlUtil.ExtractFromMp4s(new string[] { FileDic[seg]!.ActualFilePath }, 0);
|
var vtt = MP4TtmlUtil.ExtractFromMp4(FileDic[seg]!.ActualFilePath, 0);
|
||||||
//手动计算MPEGTS
|
//手动计算MPEGTS
|
||||||
if (finalVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
if (finalVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
{
|
{
|
||||||
|
@ -515,12 +515,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
FileDic.Clear();
|
FileDic.Clear();
|
||||||
var index = 0;
|
var index = 0;
|
||||||
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
var path = Path.Combine(tmpDir, index.ToString(pad) + ".fix.vtt");
|
||||||
var subContentFixed = finalVtt.ToStringWithHeader();
|
var subContentFixed = finalVtt.ToVtt();
|
||||||
//转换字幕格式
|
//转换字幕格式
|
||||||
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
if (DownloaderConfig.MyOptions.SubtitleFormat != Enum.SubtitleFormat.VTT)
|
||||||
{
|
{
|
||||||
path = Path.ChangeExtension(path, ".srt");
|
path = Path.ChangeExtension(path, ".srt");
|
||||||
subContentFixed = OtherUtil.WebVtt2Other(finalVtt, DownloaderConfig.MyOptions.SubtitleFormat);
|
subContentFixed = finalVtt.ToSrt();
|
||||||
}
|
}
|
||||||
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
await File.WriteAllTextAsync(path, subContentFixed, Encoding.UTF8);
|
||||||
FileDic[firstKey] = new DownloadResult()
|
FileDic[firstKey] = new DownloadResult()
|
||||||
|
|
|
@ -209,6 +209,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
//TryReceiveAll可以稍微缓解一下
|
//TryReceiveAll可以稍微缓解一下
|
||||||
source.TryReceiveAll(out IList<List<MediaSegment>>? segmentsList);
|
source.TryReceiveAll(out IList<List<MediaSegment>>? segmentsList);
|
||||||
var segments = segmentsList!.SelectMany(s => s);
|
var segments = segmentsList!.SelectMany(s => s);
|
||||||
|
var segmentsDuration = segments.Sum(s => s.Duration);
|
||||||
Logger.DebugMarkUp(string.Join(",", segments.Select(sss => GetSegmentName(sss, false, false))));
|
Logger.DebugMarkUp(string.Join(",", segments.Select(sss => GetSegmentName(sss, false, false))));
|
||||||
|
|
||||||
//下载init
|
//下载init
|
||||||
|
@ -355,8 +356,6 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
RecordingDurDic[task.Id] += (int)segments.Sum(s => s.Duration);
|
|
||||||
|
|
||||||
//自动修复VTT raw字幕
|
//自动修复VTT raw字幕
|
||||||
if (DownloaderConfig.MyOptions.AutoSubtitleFix && streamSpec.MediaType == Common.Enum.MediaType.SUBTITLES
|
if (DownloaderConfig.MyOptions.AutoSubtitleFix && streamSpec.MediaType == Common.Enum.MediaType.SUBTITLES
|
||||||
&& streamSpec.Extension != null && streamSpec.Extension.Contains("vtt"))
|
&& streamSpec.Extension != null && streamSpec.Extension.Contains("vtt"))
|
||||||
|
@ -372,15 +371,8 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
{
|
{
|
||||||
vtt.MpegtsTimestamp = 90000 * (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration);
|
vtt.MpegtsTimestamp = 90000 * (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration);
|
||||||
}
|
}
|
||||||
if (firstSub)
|
if (firstSub) { currentVtt = vtt; firstSub = false; }
|
||||||
{
|
else currentVtt.AddCuesFromOne(vtt);
|
||||||
currentVtt = vtt;
|
|
||||||
firstSub = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentVtt.AddCuesFromOne(vtt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,8 +393,8 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var finalVtt = MP4VttUtil.ExtractSub(mp4s, timescale);
|
var vtt = MP4VttUtil.ExtractSub(mp4s, timescale);
|
||||||
currentVtt.AddCuesFromOne(finalVtt);
|
currentVtt.AddCuesFromOne(vtt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,21 +403,40 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
if (DownloaderConfig.MyOptions.AutoSubtitleFix && streamSpec.MediaType == Common.Enum.MediaType.SUBTITLES
|
if (DownloaderConfig.MyOptions.AutoSubtitleFix && streamSpec.MediaType == Common.Enum.MediaType.SUBTITLES
|
||||||
&& streamSpec.Extension != null && streamSpec.Extension.Contains("ttml"))
|
&& streamSpec.Extension != null && streamSpec.Extension.Contains("ttml"))
|
||||||
{
|
{
|
||||||
var mp4s = FileDic.OrderBy(s => s.Key.Index).Select(s => s.Value).Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".ttml")).ToArray();
|
var keys = FileDic.OrderBy(s => s.Key.Index).Where(v => v.Value!.ActualFilePath.EndsWith(".m4s")).Select(s => s.Key);
|
||||||
if (firstSub)
|
if (firstSub)
|
||||||
{
|
{
|
||||||
if (baseTimestamp != 0)
|
if (baseTimestamp != 0)
|
||||||
{
|
{
|
||||||
var total = segments.Sum(s => s.Duration);
|
var total = segmentsDuration;
|
||||||
baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds;
|
baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds;
|
||||||
}
|
}
|
||||||
currentVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0, baseTimestamp);
|
var first = true;
|
||||||
|
foreach (var seg in keys)
|
||||||
|
{
|
||||||
|
var vtt = MP4TtmlUtil.ExtractFromTTML(FileDic[seg]!.ActualFilePath, 0, first ? baseTimestamp : 0);
|
||||||
|
//手动计算MPEGTS
|
||||||
|
if (currentVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
|
{
|
||||||
|
vtt.MpegtsTimestamp = 90000 * (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration);
|
||||||
|
}
|
||||||
|
if (first) { currentVtt = vtt; first = false; }
|
||||||
|
else currentVtt.AddCuesFromOne(vtt);
|
||||||
|
}
|
||||||
firstSub = false;
|
firstSub = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var finalVtt = MP4TtmlUtil.ExtractFromTTMLs(mp4s, 0, baseTimestamp);
|
foreach (var seg in keys)
|
||||||
currentVtt.AddCuesFromOne(finalVtt);
|
{
|
||||||
|
var vtt = MP4TtmlUtil.ExtractFromTTML(FileDic[seg]!.ActualFilePath, 0);
|
||||||
|
//手动计算MPEGTS
|
||||||
|
if (currentVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
|
{
|
||||||
|
vtt.MpegtsTimestamp = 90000 * (RecordingDurDic[task.Id] + (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration));
|
||||||
|
}
|
||||||
|
currentVtt.AddCuesFromOne(vtt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,24 +449,45 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
//var initFile = FileDic.Values.Where(v => Path.GetFileName(v!.ActualFilePath).StartsWith("_init")).FirstOrDefault();
|
//var initFile = FileDic.Values.Where(v => Path.GetFileName(v!.ActualFilePath).StartsWith("_init")).FirstOrDefault();
|
||||||
//var iniFileBytes = File.ReadAllBytes(initFile!.ActualFilePath);
|
//var iniFileBytes = File.ReadAllBytes(initFile!.ActualFilePath);
|
||||||
//var sawTtml = MP4TtmlUtil.CheckInit(iniFileBytes);
|
//var sawTtml = MP4TtmlUtil.CheckInit(iniFileBytes);
|
||||||
var mp4s = FileDic.OrderBy(s => s.Key.Index).Select(s => s.Value).Select(v => v!.ActualFilePath).Where(p => p.EndsWith(".m4s")).ToArray();
|
var keys = FileDic.OrderBy(s => s.Key.Index).Where(v => v.Value!.ActualFilePath.EndsWith(".m4s")).Select(s => s.Key);
|
||||||
if (firstSub)
|
if (firstSub)
|
||||||
{
|
{
|
||||||
if (baseTimestamp != 0)
|
if (baseTimestamp != 0)
|
||||||
{
|
{
|
||||||
var total = segments.Sum(s => s.Duration);
|
var total = segmentsDuration;
|
||||||
baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds;
|
baseTimestamp -= (long)TimeSpan.FromSeconds(total).TotalMilliseconds;
|
||||||
}
|
}
|
||||||
currentVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0, baseTimestamp);
|
var first = true;
|
||||||
|
foreach (var seg in keys)
|
||||||
|
{
|
||||||
|
var vtt = MP4TtmlUtil.ExtractFromMp4(FileDic[seg]!.ActualFilePath, 0, first ? baseTimestamp : 0);
|
||||||
|
//手动计算MPEGTS
|
||||||
|
if (currentVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
|
{
|
||||||
|
vtt.MpegtsTimestamp = 90000 * (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration);
|
||||||
|
}
|
||||||
|
if (first) { currentVtt = vtt; first = false; }
|
||||||
|
else currentVtt.AddCuesFromOne(vtt);
|
||||||
|
}
|
||||||
firstSub = false;
|
firstSub = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var finalVtt = MP4TtmlUtil.ExtractFromMp4s(mp4s, 0, baseTimestamp);
|
foreach (var seg in keys)
|
||||||
currentVtt.AddCuesFromOne(finalVtt);
|
{
|
||||||
|
var vtt = MP4TtmlUtil.ExtractFromMp4(FileDic[seg]!.ActualFilePath, 0);
|
||||||
|
//手动计算MPEGTS
|
||||||
|
if (currentVtt.MpegtsTimestamp == 0 && vtt.MpegtsTimestamp == 0)
|
||||||
|
{
|
||||||
|
vtt.MpegtsTimestamp = 90000 * (RecordingDurDic[task.Id] + (long)keys.Where(s => s.Index < seg.Index).Sum(s => s.Duration));
|
||||||
|
}
|
||||||
|
currentVtt.AddCuesFromOne(vtt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecordingDurDic[task.Id] += (int)segmentsDuration;
|
||||||
|
|
||||||
/*//写出m3u8
|
/*//写出m3u8
|
||||||
if (DownloaderConfig.MyOptions.LiveWriteHLS)
|
if (DownloaderConfig.MyOptions.LiveWriteHLS)
|
||||||
{
|
{
|
||||||
|
@ -538,10 +570,10 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
File.Delete(inputFilePath);
|
File.Delete(inputFilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var subText = currentVtt.ToStringWithHeader();
|
var subText = currentVtt.ToVtt();
|
||||||
if (outputExt == ".srt")
|
if (outputExt == ".srt")
|
||||||
{
|
{
|
||||||
subText = OtherUtil.WebVtt2Other(currentVtt, Enum.SubtitleFormat.SRT);
|
subText = currentVtt.ToSrt();
|
||||||
}
|
}
|
||||||
var subBytes = Encoding.UTF8.GetBytes(subText);
|
var subBytes = Encoding.UTF8.GetBytes(subText);
|
||||||
fileOutputStream.Position = 0;
|
fileOutputStream.Position = 0;
|
||||||
|
|
|
@ -27,40 +27,6 @@ namespace N_m3u8DL_RE.Util
|
||||||
return dic;
|
return dic;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string WebVtt2Srt(WebVttSub vtt)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
int index = 1;
|
|
||||||
foreach (var c in vtt.Cues)
|
|
||||||
{
|
|
||||||
sb.AppendLine($"{index++}");
|
|
||||||
sb.AppendLine(c.StartTime.ToString(@"hh\:mm\:ss\,fff") + " --> " + c.EndTime.ToString(@"hh\:mm\:ss\,fff"));
|
|
||||||
sb.AppendLine(c.Payload);
|
|
||||||
sb.AppendLine();
|
|
||||||
}
|
|
||||||
sb.AppendLine();
|
|
||||||
|
|
||||||
var srt = sb.ToString();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(srt.Trim()))
|
|
||||||
{
|
|
||||||
srt = "1\r\n00:00:00,000 --> 00:00:01,000"; //空字幕
|
|
||||||
}
|
|
||||||
|
|
||||||
return srt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string WebVtt2Other(WebVttSub vtt, SubtitleFormat toFormat)
|
|
||||||
{
|
|
||||||
Logger.Debug($"Convert {SubtitleFormat.VTT} ==> {toFormat}");
|
|
||||||
return toFormat switch
|
|
||||||
{
|
|
||||||
SubtitleFormat.VTT => vtt.ToStringWithHeader(),
|
|
||||||
SubtitleFormat.SRT => WebVtt2Srt(vtt),
|
|
||||||
_ => throw new NotSupportedException($"{toFormat} not supported!")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static char[] InvalidChars = "34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47"
|
private static char[] InvalidChars = "34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47"
|
||||||
.Split(',').Select(s => (char)int.Parse(s)).ToArray();
|
.Split(',').Select(s => (char)int.Parse(s)).ToArray();
|
||||||
public static string GetValidFileName(string input, string re = ".", bool filterSlash = false)
|
public static string GetValidFileName(string input, string re = ".", bool filterSlash = false)
|
||||||
|
|
Loading…
Reference in New Issue