mirror of
https://github.com/rutgersc/m3u8-rs.git
synced 2024-06-02 10:11:21 +00:00
Implemented some clippy recommendations
This commit is contained in:
parent
b84da46e0a
commit
4120e1c557
|
@ -52,7 +52,7 @@ pub fn parse_playlist(input: &[u8]) -> IResult<&[u8], Playlist> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parses an m3u8 playlist just like `parse_playlist`, except that this returns an [std::result::Result](std::result::Result) instead of a [nom::IResult](https://docs.rs/nom/1.2.3/nom/enum.IResult.html).
|
||||
/// Parses an m3u8 playlist just like `parse_playlist`, except that this returns an [std::result::Result](std::result::Result) instead of a [`nom::IResult`](https://docs.rs/nom/1.2.3/nom/enum.IResult.html).
|
||||
/// However, since [nom::IResult](nom::IResult) is now an [alias to Result](https://github.com/Geal/nom/blob/master/doc/upgrading_to_nom_5.md), this is no longer needed.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -128,7 +128,7 @@ pub fn parse_media_playlist_res(
|
|||
/// When a media tag or no master tag is found, this returns false.
|
||||
pub fn is_master_playlist(input: &[u8]) -> bool {
|
||||
// Assume it's not a master playlist
|
||||
contains_master_tag(input).map(|t| t.0).unwrap_or(false)
|
||||
contains_master_tag(input).map_or(false, |t| t.0)
|
||||
}
|
||||
|
||||
/// Scans input looking for either a master or media `#EXT` tag.
|
||||
|
@ -639,28 +639,27 @@ pub enum QuotedOrUnquoted {
|
|||
|
||||
impl Default for QuotedOrUnquoted {
|
||||
fn default() -> Self {
|
||||
QuotedOrUnquoted::Quoted(String::new())
|
||||
Self::Quoted(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl QuotedOrUnquoted {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
QuotedOrUnquoted::Quoted(s) => s.as_str(),
|
||||
QuotedOrUnquoted::Unquoted(s) => s.as_str(),
|
||||
Self::Quoted(s) | Self::Unquoted(s) => s.as_str(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_unquoted(&self) -> Option<&str> {
|
||||
match self {
|
||||
QuotedOrUnquoted::Unquoted(s) => Some(s.as_str()),
|
||||
Self::Unquoted(s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_quoted(&self) -> Option<&str> {
|
||||
match self {
|
||||
QuotedOrUnquoted::Quoted(s) => Some(s.as_str()),
|
||||
Self::Quoted(s) => Some(s.as_str()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -669,22 +668,22 @@ impl QuotedOrUnquoted {
|
|||
impl From<&str> for QuotedOrUnquoted {
|
||||
fn from(s: &str) -> Self {
|
||||
if s.starts_with('"') && s.ends_with('"') {
|
||||
return QuotedOrUnquoted::Quoted(
|
||||
return Self::Quoted(
|
||||
s.strip_prefix('"')
|
||||
.and_then(|s| s.strip_suffix('"'))
|
||||
.unwrap_or_default()
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
QuotedOrUnquoted::Unquoted(s.to_string())
|
||||
Self::Unquoted(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for QuotedOrUnquoted {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
QuotedOrUnquoted::Unquoted(s) => write!(f, "{}", s),
|
||||
QuotedOrUnquoted::Quoted(u) => write!(f, "\"{}\"", u),
|
||||
Self::Unquoted(s) => write!(f, "{}", s),
|
||||
Self::Quoted(u) => write!(f, "\"{}\"", u),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -744,18 +743,20 @@ fn float(i: &[u8]) -> IResult<&[u8], f32> {
|
|||
take_while1(is_digit),
|
||||
opt(preceded(char('.'), take_while1(is_digit))),
|
||||
),
|
||||
|(left, right): (&[u8], Option<&[u8]>)| match right {
|
||||
Some(right) => {
|
||||
let n = &i[..(left.len() + right.len() + 1)];
|
||||
// Can't fail because we validated it above already
|
||||
let n = str::from_utf8(n).unwrap();
|
||||
n.parse()
|
||||
}
|
||||
None => {
|
||||
// Can't fail because we validated it above already
|
||||
let left = str::from_utf8(left).unwrap();
|
||||
left.parse()
|
||||
}
|
||||
|(left, right): (&[u8], Option<&[u8]>)| {
|
||||
right.map_or_else(
|
||||
|| {
|
||||
// Can't fail because we validated it above already
|
||||
let left = str::from_utf8(left).unwrap();
|
||||
left.parse()
|
||||
},
|
||||
|right| {
|
||||
let n = &i[..=(left.len() + right.len())];
|
||||
// Can't fail because we validated it above already
|
||||
let n = str::from_utf8(n).unwrap();
|
||||
n.parse()
|
||||
},
|
||||
)
|
||||
},
|
||||
)(i)
|
||||
}
|
||||
|
|
155
src/playlist.rs
155
src/playlist.rs
|
@ -4,6 +4,7 @@
|
|||
//! Which is either a `MasterPlaylist` or a `MediaPlaylist`.
|
||||
|
||||
use crate::QuotedOrUnquoted;
|
||||
use chrono::DateTime;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::f32;
|
||||
|
@ -152,8 +153,8 @@ pub enum Playlist {
|
|||
impl Playlist {
|
||||
pub fn write_to<T: Write>(&self, writer: &mut T) -> std::io::Result<()> {
|
||||
match *self {
|
||||
Playlist::MasterPlaylist(ref pl) => pl.write_to(writer),
|
||||
Playlist::MediaPlaylist(ref pl) => pl.write_to(writer),
|
||||
Self::MasterPlaylist(ref pl) => pl.write_to(writer),
|
||||
Self::MediaPlaylist(ref pl) => pl.write_to(writer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,7 +255,7 @@ impl VariantStream {
|
|||
pub(crate) fn from_hashmap(
|
||||
mut attrs: HashMap<String, QuotedOrUnquoted>,
|
||||
is_i_frame: bool,
|
||||
) -> Result<VariantStream, String> {
|
||||
) -> Result<Self, String> {
|
||||
let uri = quoted_string!(attrs, "URI").unwrap_or_default();
|
||||
// TODO: keep in attrs if parsing optional attributes fails
|
||||
let bandwidth = unquoted_string_parse!(attrs, "BANDWIDTH", |s: &str| s
|
||||
|
@ -275,11 +276,11 @@ impl VariantStream {
|
|||
let subtitles = quoted_string!(attrs, "SUBTITLES");
|
||||
let closed_captions = attrs
|
||||
.remove("CLOSED-CAPTIONS")
|
||||
.map(|c| c.try_into())
|
||||
.map(TryInto::try_into)
|
||||
.transpose()?;
|
||||
let other_attributes = if attrs.is_empty() { None } else { Some(attrs) };
|
||||
|
||||
Ok(VariantStream {
|
||||
Ok(Self {
|
||||
is_i_frame,
|
||||
uri,
|
||||
bandwidth,
|
||||
|
@ -346,7 +347,7 @@ impl Display for Resolution {
|
|||
impl FromStr for Resolution {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Resolution, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s.split_once('x') {
|
||||
Some((width, height)) => {
|
||||
let width = width
|
||||
|
@ -355,7 +356,7 @@ impl FromStr for Resolution {
|
|||
let height = height
|
||||
.parse::<u64>()
|
||||
.map_err(|err| format!("Can't parse RESOLUTION attribute height: {}", err))?;
|
||||
Ok(Resolution { width, height })
|
||||
Ok(Self { width, height })
|
||||
}
|
||||
None => Err(String::from("Invalid RESOLUTION attribute")),
|
||||
}
|
||||
|
@ -373,12 +374,12 @@ pub enum HDCPLevel {
|
|||
impl FromStr for HDCPLevel {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<HDCPLevel, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"TYPE-0" => Ok(HDCPLevel::Type0),
|
||||
"TYPE-1" => Ok(HDCPLevel::Type1),
|
||||
"NONE" => Ok(HDCPLevel::None),
|
||||
_ => Ok(HDCPLevel::Other(String::from(s))),
|
||||
"TYPE-0" => Ok(Self::Type0),
|
||||
"TYPE-1" => Ok(Self::Type1),
|
||||
"NONE" => Ok(Self::None),
|
||||
_ => Ok(Self::Other(String::from(s))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -389,10 +390,10 @@ impl Display for HDCPLevel {
|
|||
f,
|
||||
"{}",
|
||||
match self {
|
||||
HDCPLevel::Type0 => "TYPE-0",
|
||||
HDCPLevel::Type1 => "TYPE-1",
|
||||
HDCPLevel::None => "NONE",
|
||||
HDCPLevel::Other(s) => s,
|
||||
Self::Type0 => "TYPE-0",
|
||||
Self::Type1 => "TYPE-1",
|
||||
Self::None => "NONE",
|
||||
Self::Other(s) => s,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -409,11 +410,11 @@ pub enum ClosedCaptionGroupId {
|
|||
impl TryFrom<QuotedOrUnquoted> for ClosedCaptionGroupId {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(s: QuotedOrUnquoted) -> Result<ClosedCaptionGroupId, String> {
|
||||
fn try_from(s: QuotedOrUnquoted) -> Result<Self, String> {
|
||||
match s {
|
||||
QuotedOrUnquoted::Unquoted(s) if s == "NONE" => Ok(ClosedCaptionGroupId::None),
|
||||
QuotedOrUnquoted::Unquoted(s) => Ok(ClosedCaptionGroupId::Other(s)),
|
||||
QuotedOrUnquoted::Quoted(s) => Ok(ClosedCaptionGroupId::GroupId(s)),
|
||||
QuotedOrUnquoted::Unquoted(s) if s == "NONE" => Ok(Self::None),
|
||||
QuotedOrUnquoted::Unquoted(s) => Ok(Self::Other(s)),
|
||||
QuotedOrUnquoted::Quoted(s) => Ok(Self::GroupId(s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -447,7 +448,7 @@ pub struct AlternativeMedia {
|
|||
impl AlternativeMedia {
|
||||
pub(crate) fn from_hashmap(
|
||||
mut attrs: HashMap<String, QuotedOrUnquoted>,
|
||||
) -> Result<AlternativeMedia, String> {
|
||||
) -> Result<Self, String> {
|
||||
let media_type = unquoted_string_parse!(attrs, "TYPE")
|
||||
.ok_or_else(|| String::from("EXT-X-MEDIA without mandatory TYPE attribute"))?;
|
||||
let uri = quoted_string!(attrs, "URI");
|
||||
|
@ -488,7 +489,7 @@ impl AlternativeMedia {
|
|||
let channels = quoted_string!(attrs, "CHANNELS");
|
||||
let other_attributes = if attrs.is_empty() { None } else { Some(attrs) };
|
||||
|
||||
Ok(AlternativeMedia {
|
||||
Ok(Self {
|
||||
media_type,
|
||||
uri,
|
||||
group_id,
|
||||
|
@ -547,20 +548,20 @@ pub enum AlternativeMediaType {
|
|||
impl FromStr for AlternativeMediaType {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<AlternativeMediaType, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"AUDIO" => Ok(AlternativeMediaType::Audio),
|
||||
"VIDEO" => Ok(AlternativeMediaType::Video),
|
||||
"SUBTITLES" => Ok(AlternativeMediaType::Subtitles),
|
||||
"CLOSED-CAPTIONS" => Ok(AlternativeMediaType::ClosedCaptions),
|
||||
_ => Ok(AlternativeMediaType::Other(String::from(s))),
|
||||
"AUDIO" => Ok(Self::Audio),
|
||||
"VIDEO" => Ok(Self::Video),
|
||||
"SUBTITLES" => Ok(Self::Subtitles),
|
||||
"CLOSED-CAPTIONS" => Ok(Self::ClosedCaptions),
|
||||
_ => Ok(Self::Other(String::from(s))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AlternativeMediaType {
|
||||
fn default() -> AlternativeMediaType {
|
||||
AlternativeMediaType::Video
|
||||
fn default() -> Self {
|
||||
Self::Video
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,11 +571,11 @@ impl Display for AlternativeMediaType {
|
|||
f,
|
||||
"{}",
|
||||
match self {
|
||||
AlternativeMediaType::Audio => "AUDIO",
|
||||
AlternativeMediaType::Video => "VIDEO",
|
||||
AlternativeMediaType::Subtitles => "SUBTITLES",
|
||||
AlternativeMediaType::ClosedCaptions => "CLOSED-CAPTIONS",
|
||||
AlternativeMediaType::Other(s) => s.as_str(),
|
||||
Self::Audio => "AUDIO",
|
||||
Self::Video => "VIDEO",
|
||||
Self::Subtitles => "SUBTITLES",
|
||||
Self::ClosedCaptions => "CLOSED-CAPTIONS",
|
||||
Self::Other(s) => s.as_str(),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -590,19 +591,19 @@ pub enum InstreamId {
|
|||
impl FromStr for InstreamId {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<InstreamId, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
if let Some(cc) = s.strip_prefix("CC") {
|
||||
let cc = cc
|
||||
.parse::<u8>()
|
||||
.map_err(|err| format!("Unable to create InstreamId from {:?}: {}", s, err))?;
|
||||
Ok(InstreamId::CC(cc))
|
||||
Ok(Self::CC(cc))
|
||||
} else if let Some(service) = s.strip_prefix("SERVICE") {
|
||||
let service = service
|
||||
.parse::<u8>()
|
||||
.map_err(|err| format!("Unable to create InstreamId from {:?}: {}", s, err))?;
|
||||
Ok(InstreamId::Service(service))
|
||||
Ok(Self::Service(service))
|
||||
} else {
|
||||
Ok(InstreamId::Other(String::from(s)))
|
||||
Ok(Self::Other(String::from(s)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -610,9 +611,9 @@ impl FromStr for InstreamId {
|
|||
impl Display for InstreamId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
InstreamId::CC(cc) => write!(f, "CC{}", cc),
|
||||
InstreamId::Service(service) => write!(f, "SERVICE{}", service),
|
||||
InstreamId::Other(s) => write!(f, "{}", s),
|
||||
Self::CC(cc) => write!(f, "CC{}", cc),
|
||||
Self::Service(service) => write!(f, "SERVICE{}", service),
|
||||
Self::Other(s) => write!(f, "{}", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +653,7 @@ pub struct SessionData {
|
|||
impl SessionData {
|
||||
pub(crate) fn from_hashmap(
|
||||
mut attrs: HashMap<String, QuotedOrUnquoted>,
|
||||
) -> Result<SessionData, String> {
|
||||
) -> Result<Self, String> {
|
||||
let data_id = quoted_string!(attrs, "DATA-ID")
|
||||
.ok_or_else(|| String::from("EXT-X-SESSION-DATA field without DATA-ID attribute"))?;
|
||||
|
||||
|
@ -665,23 +666,23 @@ impl SessionData {
|
|||
(Some(value), None) => SessionDataField::Value(value),
|
||||
(None, Some(uri)) => SessionDataField::Uri(uri),
|
||||
(Some(_), Some(_)) => {
|
||||
return Err(format![
|
||||
return Err(format!(
|
||||
"EXT-X-SESSION-DATA tag {} contains both a value and an URI",
|
||||
data_id
|
||||
])
|
||||
))
|
||||
}
|
||||
(None, None) => {
|
||||
return Err(format![
|
||||
return Err(format!(
|
||||
"EXT-X-SESSION-DATA tag {} must contain either a value or an URI",
|
||||
data_id
|
||||
])
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let language = quoted_string!(attrs, "LANGUAGE");
|
||||
let other_attributes = if attrs.is_empty() { None } else { Some(attrs) };
|
||||
|
||||
Ok(SessionData {
|
||||
Ok(Self {
|
||||
data_id,
|
||||
field,
|
||||
language,
|
||||
|
@ -786,11 +787,11 @@ pub enum MediaPlaylistType {
|
|||
impl FromStr for MediaPlaylistType {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<MediaPlaylistType, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"EVENT" => Ok(MediaPlaylistType::Event),
|
||||
"VOD" => Ok(MediaPlaylistType::Vod),
|
||||
_ => Ok(MediaPlaylistType::Other(String::from(s))),
|
||||
"EVENT" => Ok(Self::Event),
|
||||
"VOD" => Ok(Self::Vod),
|
||||
_ => Ok(Self::Other(String::from(s))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -801,17 +802,17 @@ impl Display for MediaPlaylistType {
|
|||
f,
|
||||
"{}",
|
||||
match self {
|
||||
MediaPlaylistType::Event => "EVENT",
|
||||
MediaPlaylistType::Vod => "VOD",
|
||||
MediaPlaylistType::Other(s) => s,
|
||||
Self::Event => "EVENT",
|
||||
Self::Vod => "VOD",
|
||||
Self::Other(s) => s,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MediaPlaylistType {
|
||||
fn default() -> MediaPlaylistType {
|
||||
MediaPlaylistType::Event
|
||||
fn default() -> Self {
|
||||
Self::Event
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -845,8 +846,8 @@ pub struct MediaSegment {
|
|||
}
|
||||
|
||||
impl MediaSegment {
|
||||
pub fn empty() -> MediaSegment {
|
||||
Default::default()
|
||||
pub fn empty() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub(crate) fn write_to<T: Write>(&self, w: &mut T) -> std::io::Result<()> {
|
||||
|
@ -902,19 +903,19 @@ pub enum KeyMethod {
|
|||
|
||||
impl Default for KeyMethod {
|
||||
fn default() -> Self {
|
||||
KeyMethod::None
|
||||
Self::None
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for KeyMethod {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<KeyMethod, String> {
|
||||
fn from_str(s: &str) -> Result<Self, String> {
|
||||
match s {
|
||||
"NONE" => Ok(KeyMethod::None),
|
||||
"AES-128" => Ok(KeyMethod::AES128),
|
||||
"SAMPLE-AES" => Ok(KeyMethod::SampleAES),
|
||||
_ => Ok(KeyMethod::Other(String::from(s))),
|
||||
"NONE" => Ok(Self::None),
|
||||
"AES-128" => Ok(Self::AES128),
|
||||
"SAMPLE-AES" => Ok(Self::SampleAES),
|
||||
_ => Ok(Self::Other(String::from(s))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -925,10 +926,10 @@ impl Display for KeyMethod {
|
|||
f,
|
||||
"{}",
|
||||
match self {
|
||||
KeyMethod::None => "NONE",
|
||||
KeyMethod::AES128 => "AES-128",
|
||||
KeyMethod::SampleAES => "SAMPLE-AES",
|
||||
KeyMethod::Other(s) => s,
|
||||
Self::None => "NONE",
|
||||
Self::AES128 => "AES-128",
|
||||
Self::SampleAES => "SAMPLE-AES",
|
||||
Self::Other(s) => s,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -954,7 +955,7 @@ pub struct Key {
|
|||
impl Key {
|
||||
pub(crate) fn from_hashmap(
|
||||
mut attrs: HashMap<String, QuotedOrUnquoted>,
|
||||
) -> Result<Key, String> {
|
||||
) -> Result<Self, String> {
|
||||
let method: KeyMethod = unquoted_string_parse!(attrs, "METHOD")
|
||||
.ok_or_else(|| String::from("EXT-X-KEY without mandatory METHOD attribute"))?;
|
||||
|
||||
|
@ -966,7 +967,7 @@ impl Key {
|
|||
let keyformat = quoted_string!(attrs, "KEYFORMAT");
|
||||
let keyformatversions = quoted_string!(attrs, "KEYFORMATVERSIONS");
|
||||
|
||||
Ok(Key {
|
||||
Ok(Self {
|
||||
method,
|
||||
uri,
|
||||
iv,
|
||||
|
@ -1050,7 +1051,7 @@ pub struct DateRange {
|
|||
}
|
||||
|
||||
impl DateRange {
|
||||
pub fn from_hashmap(mut attrs: HashMap<String, QuotedOrUnquoted>) -> Result<DateRange, String> {
|
||||
pub fn from_hashmap(mut attrs: HashMap<String, QuotedOrUnquoted>) -> Result<Self, String> {
|
||||
let id = quoted_string!(attrs, "ID")
|
||||
.ok_or_else(|| String::from("EXT-X-DATERANGE without mandatory ID attribute"))?;
|
||||
let class = quoted_string!(attrs, "CLASS");
|
||||
|
@ -1070,7 +1071,7 @@ impl DateRange {
|
|||
let end_on_next = is_yes!(attrs, "END-ON-NEXT");
|
||||
let mut x_prefixed = HashMap::new();
|
||||
let mut other_attributes = HashMap::new();
|
||||
for (k, v) in attrs.into_iter() {
|
||||
for (k, v) in attrs {
|
||||
if k.starts_with("X-") {
|
||||
x_prefixed.insert(k, v);
|
||||
} else {
|
||||
|
@ -1078,7 +1079,7 @@ impl DateRange {
|
|||
}
|
||||
}
|
||||
|
||||
Ok(DateRange {
|
||||
Ok(Self {
|
||||
id,
|
||||
class,
|
||||
start_date,
|
||||
|
@ -1106,7 +1107,7 @@ impl DateRange {
|
|||
write_some_attribute_quoted!(
|
||||
w,
|
||||
",END-DATE",
|
||||
&self.end_date.as_ref().map(|dt| dt.to_rfc3339())
|
||||
&self.end_date.as_ref().map(DateTime::to_rfc3339)
|
||||
)?;
|
||||
write_some_attribute!(w, ",DURATION", &self.duration)?;
|
||||
write_some_attribute!(w, ",PLANNED-DURATION", &self.planned_duration)?;
|
||||
|
@ -1146,12 +1147,12 @@ pub struct Start {
|
|||
impl Start {
|
||||
pub(crate) fn from_hashmap(
|
||||
mut attrs: HashMap<String, QuotedOrUnquoted>,
|
||||
) -> Result<Start, String> {
|
||||
) -> Result<Self, String> {
|
||||
let time_offset = unquoted_string_parse!(attrs, "TIME-OFFSET", |s: &str| s
|
||||
.parse::<f64>()
|
||||
.map_err(|err| format!("Failed to parse TIME-OFFSET attribute: {}", err)))
|
||||
.ok_or_else(|| String::from("EXT-X-START without mandatory TIME-OFFSET attribute"))?;
|
||||
Ok(Start {
|
||||
Ok(Self {
|
||||
time_offset,
|
||||
precise: is_yes!(attrs, "PRECISE").into(),
|
||||
other_attributes: attrs,
|
||||
|
|
Loading…
Reference in a new issue