///|
pub(all) enum PlaylistKind {
Empty
Media
Master
Hybrid
} derive(Eq, @debug.Debug)
///|
pub(all) enum Severity {
Error
Warning
Info
} derive(Eq, @debug.Debug)
///|
pub(all) enum ParseError {
MissingHeader(Int)
InvalidTag(Int, String)
InvalidAttribute(Int, String)
InvalidNumber(Int, String, String)
UriWithoutContext(Int, String)
MissingSegmentUri(Int)
MissingVariantUri(Int)
} derive(Eq, @debug.Debug)
///|
pub(all) struct HlsAttribute {
name : String
value : String
quoted : Bool
} derive(Eq, @debug.Debug)
///|
pub(all) struct ByteRange {
length : Int
offset : Int?
} derive(Eq, @debug.Debug)
///|
pub(all) struct KeyInfo {
key_method : String
uri : String?
iv : String?
key_format : String?
key_format_versions : String?
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct SegmentMap {
uri : String
byte_range : ByteRange?
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct Segment {
uri : String
title : String
duration_ms : Int
byte_range : ByteRange?
key : KeyInfo?
map : SegmentMap?
discontinuity : Bool
program_date_time : String?
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct Resolution {
width : Int
height : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct VariantStream {
uri : String
bandwidth : Int
average_bandwidth : Int?
codecs : String?
resolution : Resolution?
frame_rate_milli : Int?
audio_group : String?
subtitles_group : String?
closed_captions : String?
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct Rendition {
rendition_type : String
group_id : String
name : String
language : String?
uri : String?
default : Bool
autoselect : Bool
forced : Bool
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct HlsPlaylist {
version : Int
target_duration : Int
media_sequence : Int
discontinuity_sequence : Int
start_offset_ms : Int?
end_list : Bool
independent_segments : Bool
segments : Array[Segment]
variants : Array[VariantStream]
renditions : Array[Rendition]
unknown_tags : Array[String]
kind : PlaylistKind
} derive(Eq, @debug.Debug)
///|
pub(all) struct ValidationIssue {
severity : Severity
code : String
message : String
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct ValidationReport {
ok : Bool
errors : Int
warnings : Int
infos : Int
issues : Array[ValidationIssue]
} derive(Eq, @debug.Debug)
///|
pub(all) struct PlaylistStats {
kind : PlaylistKind
segment_count : Int
variant_count : Int
rendition_count : Int
total_duration_ms : Int
max_segment_ms : Int
encrypted_segments : Int
discontinuities : Int
} derive(Eq, @debug.Debug)
///|
pub(all) enum UriRole {
SegmentUri
VariantUri
RenditionUri
KeyUri
MapUri
} derive(Eq, @debug.Debug)
///|
pub(all) struct UriEntry {
role : UriRole
uri : String
line : Int
} derive(Eq, @debug.Debug)
///|
pub(all) struct UriAudit {
total : Int
absolute_uris : Int
relative_uris : Int
data_uris : Int
empty_uris : Int
parent_traversal_uris : Int
entries : Array[UriEntry]
} derive(Eq, @debug.Debug)
///|
pub(all) struct LadderReport {
variants : Int
lowest_bandwidth : Int
highest_bandwidth : Int
monotonic : Bool
duplicate_bandwidths : Int
has_resolution_gap : Bool
} derive(Eq, @debug.Debug)
///|
pub fn ParseError::message(self : ParseError) -> String {
match self {
MissingHeader(line) =>
"line \{line}: expected #EXTM3U before playlist content"
InvalidTag(line, reason) => "line \{line}: invalid tag: \{reason}"
InvalidAttribute(line, reason) =>
"line \{line}: invalid attribute list: \{reason}"
InvalidNumber(line, field, value) =>
"line \{line}: invalid number for \{field}: \{value}"
UriWithoutContext(line, uri) =>
"line \{line}: uri has no pending segment or variant tag: \{uri}"
MissingSegmentUri(line) =>
"line \{line}: #EXTINF must be followed by a media segment URI"
MissingVariantUri(line) =>
"line \{line}: #EXT-X-STREAM-INF must be followed by a variant URI"
}
}
///|
pub fn ValidationIssue::error(
code : String,
message : String,
line~ : Int = 0,
) -> ValidationIssue {
{ severity: Error, code, message, line }
}
///|
pub fn ValidationIssue::warning(
code : String,
message : String,
line~ : Int = 0,
) -> ValidationIssue {
{ severity: Warning, code, message, line }
}
///|
pub fn ValidationIssue::info(
code : String,
message : String,
line~ : Int = 0,
) -> ValidationIssue {
{ severity: Info, code, message, line }
}
///|
pub fn HlsPlaylist::empty() -> HlsPlaylist {
{
version: 0,
target_duration: 0,
media_sequence: 0,
discontinuity_sequence: 0,
start_offset_ms: None,
end_list: false,
independent_segments: false,
segments: [],
variants: [],
renditions: [],
unknown_tags: [],
kind: Empty,
}
}