test(core/browser/platform): 26 extreme RED/GREEN TDD cycles and full regression hardening (3,235 PASS)
Some checks failed
release / test (push) Failing after 14m5s
release / windows (push) Has been cancelled
release / android (push) Has been cancelled
release / linux (push) Has been cancelled
release / macos (push) Has been cancelled

This commit is contained in:
Yun Chan 2026-09-18 23:32:32 +09:00
parent bcd242691f
commit 8677853822
100 changed files with 4814 additions and 333 deletions

View file

@ -31,9 +31,11 @@ public static class M3u8Parser
var variants = new List<Variant>();
var segments = new List<Segment>();
Uri? init = null;
long? initByteRangeLen = null;
long? initByteRangeOff = null;
bool isMaster = false;
if (string.IsNullOrWhiteSpace(text) || !text.Contains("#EXTM3U", StringComparison.OrdinalIgnoreCase))
if (baseUrl == null || string.IsNullOrWhiteSpace(text) || !text.Contains("#EXTM3U", StringComparison.OrdinalIgnoreCase))
{
return new ParsedPlaylist
{
@ -41,6 +43,8 @@ public static class M3u8Parser
Variants = variants,
Segments = segments,
InitSegment = init,
InitByteRangeLength = initByteRangeLen,
InitByteRangeOffset = initByteRangeOff,
};
}
@ -49,6 +53,11 @@ public static class M3u8Parser
long seq = 0;
int idx = 0;
long? pendingByteRangeLength = null;
long? pendingByteRangeOffset = null;
long prevByteRangeOffset = 0;
long prevByteRangeLength = 0;
using var reader = new StringReader(text);
string? raw;
while ((raw = reader.ReadLine()) != null)
@ -64,7 +73,7 @@ public static class M3u8Parser
if (line.StartsWith("#EXT-X-MEDIA-SEQUENCE:", StringComparison.OrdinalIgnoreCase))
{
var parts = line.Split(':', 2);
if (parts.Length > 1 && long.TryParse(parts[1].Trim(), out var s)) seq = s;
if (parts.Length > 1 && long.TryParse(parts[1].Trim(), out var s) && s >= 0) seq = s;
continue;
}
if (line.StartsWith("#EXT-X-KEY:", StringComparison.OrdinalIgnoreCase))
@ -78,11 +87,46 @@ public static class M3u8Parser
: null;
continue;
}
if (line.StartsWith("#EXT-X-BYTERANGE:", StringComparison.OrdinalIgnoreCase))
{
var val = line.Substring("#EXT-X-BYTERANGE:".Length).Trim();
var parts = val.Split('@', 2);
if (long.TryParse(parts[0].Trim(), out var len) && len > 0)
{
pendingByteRangeLength = len;
if (parts.Length > 1 && long.TryParse(parts[1].Trim(), out var off) && off >= 0)
{
pendingByteRangeOffset = off;
prevByteRangeOffset = off;
}
else
{
pendingByteRangeOffset = prevByteRangeOffset + prevByteRangeLength;
prevByteRangeOffset = pendingByteRangeOffset.Value;
}
prevByteRangeLength = len;
}
continue;
}
if (line.StartsWith("#EXT-X-MAP:", StringComparison.OrdinalIgnoreCase))
{
var a = ParseAttrs(line.Substring("#EXT-X-MAP:".Length));
if (a.TryGetValue("URI", out var u) && !string.IsNullOrEmpty(u) && Uri.TryCreate(baseUrl, u.Trim('"'), out var mu))
init = mu;
if (a.TryGetValue("BYTERANGE", out var br) && !string.IsNullOrEmpty(br))
{
var cleanBr = br.Trim('"');
var brParts = cleanBr.Split('@', 2);
if (long.TryParse(brParts[0].Trim(), out var bLen) && bLen > 0)
{
initByteRangeLen = bLen;
if (brParts.Length > 1 && long.TryParse(brParts[1].Trim(), out var bOff) && bOff >= 0)
{
initByteRangeOff = bOff;
}
}
}
continue;
}
if (line.StartsWith("#")) continue;
@ -93,15 +137,18 @@ public static class M3u8Parser
if (pendingVariant != null)
{
int.TryParse(pendingVariant.GetValue("BANDWIDTH", "0"), out var bw);
variants.Add(new Variant(abs, bw,
variants.Add(new Variant(abs, Math.Max(0, bw),
pendingVariant.GetValue("RESOLUTION"), pendingVariant.GetValue("CODECS")));
pendingVariant = null;
isMaster = true;
}
else
{
segments.Add(new Segment(abs, idx, seq, curKey));
idx++; seq++;
segments.Add(new Segment(abs, idx, seq, curKey, pendingByteRangeLength, pendingByteRangeOffset));
pendingByteRangeLength = null;
pendingByteRangeOffset = null;
idx++;
if (seq < long.MaxValue) seq++;
}
}
@ -111,6 +158,8 @@ public static class M3u8Parser
Variants = variants,
Segments = segments,
InitSegment = init,
InitByteRangeLength = initByteRangeLen,
InitByteRangeOffset = initByteRangeOff,
};
}
}