mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-09-27 14:10:05 +00:00
parent
448c331447
commit
ac80ac5c9d
17 changed files with 115 additions and 141 deletions
|
@ -16,7 +16,7 @@ travis-ci = { repository = "sile/hls_m3u8" }
|
||||||
codecov = { repository = "sile/hls_m3u8" }
|
codecov = { repository = "sile/hls_m3u8" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
failure = "0.1.5"
|
thiserror = "1.0"
|
||||||
derive_builder = "0.8.0"
|
derive_builder = "0.8.0"
|
||||||
chrono = "0.4.9"
|
chrono = "0.4.9"
|
||||||
strum = { version = "0.16.0", features = ["derive"] }
|
strum = { version = "0.16.0", features = ["derive"] }
|
||||||
|
|
179
src/error.rs
179
src/error.rs
|
@ -1,39 +1,33 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use failure::{Backtrace, Context, Fail};
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::types::ProtocolVersion;
|
||||||
|
|
||||||
/// This crate specific `Result` type.
|
/// This crate specific `Result` type.
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
/// The [`ErrorKind`].
|
/// The [`ErrorKind`].
|
||||||
#[derive(Debug, Fail, Clone, PartialEq, Eq)]
|
#[derive(Debug, Error, Clone, PartialEq)]
|
||||||
pub enum ErrorKind {
|
enum ErrorKind {
|
||||||
#[fail(display = "ChronoParseError: {}", _0)]
|
|
||||||
/// An error from the [Chrono](chrono) crate.
|
|
||||||
ChronoParseError(String),
|
|
||||||
|
|
||||||
#[fail(display = "UnknownError: {}", _0)]
|
|
||||||
/// An unknown error occured.
|
|
||||||
UnknownError(String),
|
|
||||||
|
|
||||||
#[fail(display = "A value is missing for the attribute {}", _0)]
|
|
||||||
/// A required value is missing.
|
/// A required value is missing.
|
||||||
|
#[error("A value is missing for the attribute {}", _0)]
|
||||||
MissingValue(String),
|
MissingValue(String),
|
||||||
|
|
||||||
#[fail(display = "Invalid Input")]
|
|
||||||
/// Error for anything.
|
/// Error for anything.
|
||||||
|
#[error("Invalid Input")]
|
||||||
InvalidInput,
|
InvalidInput,
|
||||||
|
|
||||||
#[fail(display = "ParseIntError: {}", _0)]
|
#[error("{}", _0)]
|
||||||
/// Failed to parse a String to int.
|
/// Failed to parse a String to int.
|
||||||
ParseIntError(String),
|
ParseIntError(::std::num::ParseIntError),
|
||||||
|
|
||||||
#[fail(display = "ParseFloatError: {}", _0)]
|
#[error("{}", _0)]
|
||||||
/// Failed to parse a String to float.
|
/// Failed to parse a String to float.
|
||||||
ParseFloatError(String),
|
ParseFloatError(::std::num::ParseFloatError),
|
||||||
|
|
||||||
#[fail(display = "MissingTag: Expected {} at the start of {:?}", tag, input)]
|
|
||||||
/// A tag is missing, that is required at the start of the input.
|
/// A tag is missing, that is required at the start of the input.
|
||||||
|
#[error("Expected `{}` at the start of {:?}", tag, input)]
|
||||||
MissingTag {
|
MissingTag {
|
||||||
/// The required tag.
|
/// The required tag.
|
||||||
tag: String,
|
tag: String,
|
||||||
|
@ -41,100 +35,98 @@ pub enum ErrorKind {
|
||||||
input: String,
|
input: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[fail(display = "CustomError: {}", _0)]
|
#[error("{}", _0)]
|
||||||
/// A custom error.
|
/// A custom error.
|
||||||
Custom(String),
|
Custom(String),
|
||||||
|
|
||||||
#[fail(display = "Unmatched Group: {:?}", _0)]
|
|
||||||
/// Unmatched Group
|
/// Unmatched Group
|
||||||
|
#[error("Unmatched Group: {:?}", _0)]
|
||||||
UnmatchedGroup(String),
|
UnmatchedGroup(String),
|
||||||
|
|
||||||
#[fail(display = "Unknown Protocol version: {:?}", _0)]
|
|
||||||
/// Unknown m3u8 version. This library supports up to ProtocolVersion 7.
|
/// Unknown m3u8 version. This library supports up to ProtocolVersion 7.
|
||||||
|
#[error("Unknown protocol version {:?}", _0)]
|
||||||
UnknownProtocolVersion(String),
|
UnknownProtocolVersion(String),
|
||||||
|
|
||||||
#[fail(display = "IoError: {}", _0)]
|
|
||||||
/// Some io error
|
/// Some io error
|
||||||
|
#[error("{}", _0)]
|
||||||
Io(String),
|
Io(String),
|
||||||
|
|
||||||
#[fail(
|
|
||||||
display = "VersionError: required_version: {:?}, specified_version: {:?}",
|
|
||||||
_0, _1
|
|
||||||
)]
|
|
||||||
/// This error occurs, if there is a ProtocolVersion mismatch.
|
/// This error occurs, if there is a ProtocolVersion mismatch.
|
||||||
VersionError(String, String),
|
#[error("required_version: {:?}, specified_version: {:?}", _0, _1)]
|
||||||
|
VersionError(ProtocolVersion, ProtocolVersion),
|
||||||
|
|
||||||
#[fail(display = "BuilderError: {}", _0)]
|
|
||||||
/// An Error from a Builder.
|
|
||||||
BuilderError(String),
|
|
||||||
|
|
||||||
#[fail(display = "Missing Attribute: {}", _0)]
|
|
||||||
/// An attribute is missing.
|
/// An attribute is missing.
|
||||||
|
#[error("Missing Attribute: {}", _0)]
|
||||||
MissingAttribute(String),
|
MissingAttribute(String),
|
||||||
|
|
||||||
#[fail(display = "Unexpected Attribute: {:?}", _0)]
|
|
||||||
/// An unexpected value.
|
/// An unexpected value.
|
||||||
|
#[error("Unexpected Attribute: {:?}", _0)]
|
||||||
UnexpectedAttribute(String),
|
UnexpectedAttribute(String),
|
||||||
|
|
||||||
#[fail(display = "Unexpected Tag: {:?}", _0)]
|
|
||||||
/// An unexpected tag.
|
/// An unexpected tag.
|
||||||
|
#[error("Unexpected Tag: {:?}", _0)]
|
||||||
UnexpectedTag(String),
|
UnexpectedTag(String),
|
||||||
|
|
||||||
|
/// An error from the [`chrono`] crate.
|
||||||
|
#[error("{}", _0)]
|
||||||
|
ChronoParseError(chrono::ParseError),
|
||||||
|
|
||||||
|
/// An error from a Builder.
|
||||||
|
#[error("BuilderError: {}", _0)]
|
||||||
|
Builder(String),
|
||||||
|
|
||||||
|
#[error("{}", _0)]
|
||||||
|
Hex(hex::FromHexError),
|
||||||
|
|
||||||
/// Hints that destructuring should not be exhaustive.
|
/// Hints that destructuring should not be exhaustive.
|
||||||
///
|
///
|
||||||
/// This enum may grow additional variants, so this makes sure clients
|
/// This enum may grow additional variants, so this makes sure clients
|
||||||
/// don't count on exhaustive matching. (Otherwise, adding a new variant
|
/// don't count on exhaustive matching. (Otherwise, adding a new variant
|
||||||
/// could break existing code.)
|
/// could break existing code.)
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[fail(display = "Invalid error")]
|
#[error("Invalid error")]
|
||||||
__Nonexhaustive,
|
__Nonexhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// The Error type of this library.
|
/// The Error type of this library.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
inner: Context<ErrorKind>,
|
inner: ErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fail for Error {
|
impl std::error::Error for Error {}
|
||||||
fn cause(&self) -> Option<&dyn Fail> { self.inner.cause() }
|
|
||||||
|
|
||||||
fn backtrace(&self) -> Option<&Backtrace> { self.inner.backtrace() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) }
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.inner.fmt(f) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ErrorKind> for Error {
|
|
||||||
fn from(kind: ErrorKind) -> Self { Self::from(Context::new(kind)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Context<ErrorKind>> for Error {
|
|
||||||
fn from(inner: Context<ErrorKind>) -> Self { Self { inner } }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
|
fn new(inner: ErrorKind) -> Self { Self { inner } }
|
||||||
|
|
||||||
|
pub(crate) fn custom<T: fmt::Display>(value: T) -> Self {
|
||||||
|
Self::new(ErrorKind::Custom(value.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn missing_value<T: ToString>(value: T) -> Self {
|
pub(crate) fn missing_value<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::MissingValue(value.to_string()))
|
Self::new(ErrorKind::MissingValue(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unexpected_attribute<T: ToString>(value: T) -> Self {
|
pub(crate) fn unexpected_attribute<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::UnexpectedAttribute(value.to_string()))
|
Self::new(ErrorKind::UnexpectedAttribute(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unexpected_tag<T: ToString>(value: T) -> Self {
|
pub(crate) fn unexpected_tag<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::UnexpectedTag(value.to_string()))
|
Self::new(ErrorKind::UnexpectedTag(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn invalid_input() -> Self { Self::from(ErrorKind::InvalidInput) }
|
pub(crate) fn invalid_input() -> Self { Self::new(ErrorKind::InvalidInput) }
|
||||||
|
|
||||||
pub(crate) fn parse_int_error<T: ToString>(value: T) -> Self {
|
pub(crate) fn parse_int(value: ::std::num::ParseIntError) -> Self {
|
||||||
Self::from(ErrorKind::ParseIntError(value.to_string()))
|
Self::new(ErrorKind::ParseIntError(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn parse_float_error<T: ToString>(value: T) -> Self {
|
pub(crate) fn parse_float(value: ::std::num::ParseFloatError) -> Self {
|
||||||
Self::from(ErrorKind::ParseFloatError(value.to_string()))
|
Self::new(ErrorKind::ParseFloatError(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn missing_tag<T, U>(tag: T, input: U) -> Self
|
pub(crate) fn missing_tag<T, U>(tag: T, input: U) -> Self
|
||||||
|
@ -142,76 +134,53 @@ impl Error {
|
||||||
T: ToString,
|
T: ToString,
|
||||||
U: ToString,
|
U: ToString,
|
||||||
{
|
{
|
||||||
Self::from(ErrorKind::MissingTag {
|
Self::new(ErrorKind::MissingTag {
|
||||||
tag: tag.to_string(),
|
tag: tag.to_string(),
|
||||||
input: input.to_string(),
|
input: input.to_string(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unmatched_group<T: ToString>(value: T) -> Self {
|
pub(crate) fn unmatched_group<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::UnmatchedGroup(value.to_string()))
|
Self::new(ErrorKind::UnmatchedGroup(value.to_string()))
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn custom<T>(value: T) -> Self
|
|
||||||
where
|
|
||||||
T: fmt::Display,
|
|
||||||
{
|
|
||||||
Self::from(ErrorKind::Custom(value.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unknown_protocol_version<T: ToString>(value: T) -> Self {
|
pub(crate) fn unknown_protocol_version<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::UnknownProtocolVersion(value.to_string()))
|
Self::new(ErrorKind::UnknownProtocolVersion(value.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn io<T: ToString>(value: T) -> Self { Self::from(ErrorKind::Io(value.to_string())) }
|
pub(crate) fn io<T: ToString>(value: T) -> Self { Self::new(ErrorKind::Io(value.to_string())) }
|
||||||
|
|
||||||
pub(crate) fn builder_error<T: ToString>(value: T) -> Self {
|
pub(crate) fn builder<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::BuilderError(value.to_string()))
|
Self::new(ErrorKind::Builder(value.to_string()))
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn chrono<T: ToString>(value: T) -> Self {
|
|
||||||
Self::from(ErrorKind::ChronoParseError(value.to_string()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn missing_attribute<T: ToString>(value: T) -> Self {
|
pub(crate) fn missing_attribute<T: ToString>(value: T) -> Self {
|
||||||
Self::from(ErrorKind::MissingAttribute(value.to_string()))
|
Self::new(ErrorKind::MissingAttribute(value.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// third party crates:
|
||||||
|
pub(crate) fn chrono(value: chrono::format::ParseError) -> Self {
|
||||||
|
Self::new(ErrorKind::ChronoParseError(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn hex(value: hex::FromHexError) -> Self { Self::new(ErrorKind::Hex(value)) }
|
||||||
|
|
||||||
|
pub(crate) fn strum(value: strum::ParseError) -> Self {
|
||||||
|
Self::new(ErrorKind::Custom(value.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
impl From<::std::num::ParseIntError> for Error {
|
impl From<::std::num::ParseIntError> for Error {
|
||||||
fn from(value: ::std::num::ParseIntError) -> Self { Self::parse_int_error(value) }
|
fn from(value: ::std::num::ParseIntError) -> Self { Self::parse_int(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
impl From<::std::num::ParseFloatError> for Error {
|
impl From<::std::num::ParseFloatError> for Error {
|
||||||
fn from(value: ::std::num::ParseFloatError) -> Self { Self::parse_float_error(value) }
|
fn from(value: ::std::num::ParseFloatError) -> Self { Self::parse_float(value) }
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::std::io::Error> for Error {
|
|
||||||
fn from(value: ::std::io::Error) -> Self { Self::io(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::chrono::ParseError> for Error {
|
|
||||||
fn from(value: ::chrono::ParseError) -> Self { Self::chrono(value) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
impl From<::strum::ParseError> for Error {
|
impl From<::strum::ParseError> for Error {
|
||||||
fn from(value: ::strum::ParseError) -> Self {
|
fn from(value: ::strum::ParseError) -> Self { Self::strum(value) }
|
||||||
Self::custom(value) // TODO!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Error {
|
|
||||||
fn from(value: String) -> Self { Self::custom(value) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::core::convert::Infallible> for Error {
|
|
||||||
fn from(_: ::core::convert::Infallible) -> Self {
|
|
||||||
Self::custom("An Infallible error has been returned! (this should never happen!)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<::hex::FromHexError> for Error {
|
|
||||||
fn from(value: ::hex::FromHexError) -> Self {
|
|
||||||
Self::custom(value) // TODO!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,16 +65,15 @@ impl MasterPlaylist {
|
||||||
/// Returns a Builder for a [`MasterPlaylist`].
|
/// Returns a Builder for a [`MasterPlaylist`].
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use hls_m3u8::tags::ExtXStart;
|
/// use hls_m3u8::tags::ExtXStart;
|
||||||
/// use hls_m3u8::MasterPlaylist;
|
/// use hls_m3u8::MasterPlaylist;
|
||||||
///
|
///
|
||||||
/// # fn main() -> Result<(), hls_m3u8::Error> {
|
|
||||||
/// MasterPlaylist::builder()
|
/// MasterPlaylist::builder()
|
||||||
/// .start_tag(ExtXStart::new(20.123456))
|
/// .start_tag(ExtXStart::new(20.123456))
|
||||||
/// .build()?;
|
/// .build()?;
|
||||||
/// # Ok(())
|
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
pub fn builder() -> MasterPlaylistBuilder { MasterPlaylistBuilder::default() }
|
pub fn builder() -> MasterPlaylistBuilder { MasterPlaylistBuilder::default() }
|
||||||
|
|
||||||
|
@ -438,7 +437,7 @@ impl FromStr for MasterPlaylist {
|
||||||
builder.session_data_tags(session_data_tags);
|
builder.session_data_tags(session_data_tags);
|
||||||
builder.session_key_tags(session_key_tags);
|
builder.session_key_tags(session_key_tags);
|
||||||
|
|
||||||
builder.build().map_err(Error::builder_error)
|
builder.build().map_err(Error::builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,7 +353,7 @@ fn parse_media_playlist(
|
||||||
Line::Uri(uri) => {
|
Line::Uri(uri) => {
|
||||||
segment.uri(uri);
|
segment.uri(uri);
|
||||||
segment.keys(available_key_tags.clone());
|
segment.keys(available_key_tags.clone());
|
||||||
segments.push(segment.build().map_err(Error::builder_error)?);
|
segments.push(segment.build().map_err(Error::builder)?);
|
||||||
segment = MediaSegment::builder();
|
segment = MediaSegment::builder();
|
||||||
has_partial_segment = false;
|
has_partial_segment = false;
|
||||||
}
|
}
|
||||||
|
@ -365,7 +365,7 @@ fn parse_media_playlist(
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.segments(segments);
|
builder.segments(segments);
|
||||||
builder.build().map_err(Error::builder_error)
|
builder.build().map_err(Error::builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for MediaPlaylist {
|
impl FromStr for MediaPlaylist {
|
||||||
|
|
|
@ -12,18 +12,18 @@ use crate::{Error, RequiredVersion};
|
||||||
/// It is the at the start of every [`Media Playlist`] and [`Master Playlist`].
|
/// It is the at the start of every [`Media Playlist`] and [`Master Playlist`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
///
|
||||||
/// Parsing from a [`str`]:
|
/// Parsing from a [`str`]:
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use failure::Error;
|
|
||||||
/// # use hls_m3u8::tags::ExtM3u;
|
/// # use hls_m3u8::tags::ExtM3u;
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() -> Result<(), Error> {
|
|
||||||
/// assert_eq!("#EXTM3U".parse::<ExtM3u>()?, ExtM3u);
|
/// assert_eq!("#EXTM3U".parse::<ExtM3u>()?, ExtM3u);
|
||||||
/// #
|
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
/// Converting to a [`str`]:
|
/// Converting to a [`str`]:
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use hls_m3u8::tags::ExtM3u;
|
/// # use hls_m3u8::tags::ExtM3u;
|
||||||
/// #
|
/// #
|
||||||
|
|
|
@ -12,21 +12,18 @@ use crate::{Error, RequiredVersion};
|
||||||
/// It applies to the entire Playlist.
|
/// It applies to the entire Playlist.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
///
|
||||||
/// Parsing from a [`str`]:
|
/// Parsing from a [`str`]:
|
||||||
/// ```
|
/// ```
|
||||||
/// # use failure::Error;
|
|
||||||
/// # use hls_m3u8::tags::ExtXVersion;
|
/// # use hls_m3u8::tags::ExtXVersion;
|
||||||
/// #
|
/// #
|
||||||
/// # fn main() -> Result<(), Error> {
|
|
||||||
/// use hls_m3u8::types::ProtocolVersion;
|
/// use hls_m3u8::types::ProtocolVersion;
|
||||||
///
|
///
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// "#EXT-X-VERSION:5".parse::<ExtXVersion>()?,
|
/// "#EXT-X-VERSION:5".parse::<ExtXVersion>()?,
|
||||||
/// ExtXVersion::new(ProtocolVersion::V5)
|
/// ExtXVersion::new(ProtocolVersion::V5)
|
||||||
/// );
|
/// );
|
||||||
/// #
|
/// # Ok::<(), Box<dyn ::std::error::Error>>(())
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
/// ```
|
||||||
/// Converting to a [`str`]:
|
/// Converting to a [`str`]:
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -85,7 +85,7 @@ impl ExtXIFrameStreamInfBuilder {
|
||||||
.uri
|
.uri
|
||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| Error::missing_value("frame rate"))?,
|
.ok_or_else(|| Error::missing_value("frame rate"))?,
|
||||||
stream_inf: self.stream_inf.build().map_err(Error::builder_error)?,
|
stream_inf: self.stream_inf.build().map_err(Error::builder)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -735,7 +735,7 @@ impl FromStr for ExtXMedia {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.build().map_err(Error::builder_error)
|
builder.build().map_err(Error::builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ impl ExtXStreamInfBuilder {
|
||||||
audio: self.audio.clone(),
|
audio: self.audio.clone(),
|
||||||
subtitles: self.subtitles.clone(),
|
subtitles: self.subtitles.clone(),
|
||||||
closed_captions: self.closed_captions.clone(),
|
closed_captions: self.closed_captions.clone(),
|
||||||
stream_inf: self.stream_inf.build().map_err(Error::builder_error)?,
|
stream_inf: self.stream_inf.build().map_err(Error::builder)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ impl FromStr for ExtXStreamInf {
|
||||||
"FRAME-RATE" => frame_rate = Some((value.parse())?),
|
"FRAME-RATE" => frame_rate = Some((value.parse())?),
|
||||||
"AUDIO" => audio = Some(unquote(value)),
|
"AUDIO" => audio = Some(unquote(value)),
|
||||||
"SUBTITLES" => subtitles = Some(unquote(value)),
|
"SUBTITLES" => subtitles = Some(unquote(value)),
|
||||||
"CLOSED-CAPTIONS" => closed_captions = Some(value.parse()?),
|
"CLOSED-CAPTIONS" => closed_captions = Some(value.parse().unwrap()),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -719,7 +719,7 @@ impl FromStr for ExtXDateRange {
|
||||||
"ID" => id = Some(unquote(value)),
|
"ID" => id = Some(unquote(value)),
|
||||||
"CLASS" => class = Some(unquote(value)),
|
"CLASS" => class = Some(unquote(value)),
|
||||||
"START-DATE" => start_date = Some(unquote(value)),
|
"START-DATE" => start_date = Some(unquote(value)),
|
||||||
"END-DATE" => end_date = Some(unquote(value).parse()?),
|
"END-DATE" => end_date = Some(unquote(value).parse().map_err(Error::chrono)?),
|
||||||
"DURATION" => {
|
"DURATION" => {
|
||||||
duration = Some(Duration::from_secs_f64(value.parse()?));
|
duration = Some(Duration::from_secs_f64(value.parse()?));
|
||||||
}
|
}
|
||||||
|
@ -750,7 +750,8 @@ impl FromStr for ExtXDateRange {
|
||||||
let id = id.ok_or_else(|| Error::missing_value("ID"))?;
|
let id = id.ok_or_else(|| Error::missing_value("ID"))?;
|
||||||
let start_date = start_date
|
let start_date = start_date
|
||||||
.ok_or_else(|| Error::missing_value("START-DATE"))?
|
.ok_or_else(|| Error::missing_value("START-DATE"))?
|
||||||
.parse()?;
|
.parse()
|
||||||
|
.map_err(Error::chrono)?;
|
||||||
|
|
||||||
if end_on_next && class.is_none() {
|
if end_on_next && class.is_none() {
|
||||||
return Err(Error::invalid_input());
|
return Err(Error::invalid_input());
|
||||||
|
|
|
@ -114,7 +114,7 @@ impl FromStr for ExtXProgramDateTime {
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
let input = tag(input, Self::PREFIX)?;
|
let input = tag(input, Self::PREFIX)?;
|
||||||
|
|
||||||
let date_time = DateTime::parse_from_rfc3339(input)?;
|
let date_time = DateTime::parse_from_rfc3339(input).map_err(Error::chrono)?;
|
||||||
Ok(Self::new(date_time))
|
Ok(Self::new(date_time))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,8 @@ impl FromStr for Channels {
|
||||||
let channel_number = parameters
|
let channel_number = parameters
|
||||||
.first()
|
.first()
|
||||||
.ok_or_else(|| Error::missing_attribute("First parameter of channels!"))?
|
.ok_or_else(|| Error::missing_attribute("First parameter of channels!"))?
|
||||||
.parse()?;
|
.parse()
|
||||||
|
.map_err(Error::parse_int)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
channel_number,
|
channel_number,
|
||||||
|
|
|
@ -40,7 +40,9 @@ impl DecimalFloatingPoint {
|
||||||
impl FromStr for DecimalFloatingPoint {
|
impl FromStr for DecimalFloatingPoint {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> { Self::new(input.parse()?) }
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
|
Self::new(input.parse().map_err(Error::parse_float)?)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for DecimalFloatingPoint {
|
impl Deref for DecimalFloatingPoint {
|
||||||
|
|
|
@ -59,8 +59,8 @@ impl FromStr for DecimalResolution {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
width: tokens[0].parse()?,
|
width: tokens[0].parse().map_err(Error::parse_int)?,
|
||||||
height: tokens[1].parse()?,
|
height: tokens[1].parse().map_err(Error::parse_int)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,11 +295,11 @@ impl FromStr for DecryptionKey {
|
||||||
|
|
||||||
for (key, value) in input.parse::<AttributePairs>()? {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
match key.as_str() {
|
match key.as_str() {
|
||||||
"METHOD" => method = Some(value.parse()?),
|
"METHOD" => method = Some(value.parse().map_err(Error::strum)?),
|
||||||
"URI" => uri = Some(unquote(value)),
|
"URI" => uri = Some(unquote(value)),
|
||||||
"IV" => iv = Some(value.parse()?),
|
"IV" => iv = Some(value.parse()?),
|
||||||
"KEYFORMAT" => key_format = Some(value.parse()?),
|
"KEYFORMAT" => key_format = Some(value.parse()?),
|
||||||
"KEYFORMATVERSIONS" => key_format_versions = Some(value.parse()?),
|
"KEYFORMATVERSIONS" => key_format_versions = Some(value.parse().unwrap()),
|
||||||
_ => {
|
_ => {
|
||||||
// [6.3.1. General Client Responsibilities]
|
// [6.3.1. General Client Responsibilities]
|
||||||
// > ignore any attribute/value pair with an unrecognized
|
// > ignore any attribute/value pair with an unrecognized
|
||||||
|
|
|
@ -270,11 +270,15 @@ impl FromStr for StreamInf {
|
||||||
|
|
||||||
for (key, value) in input.parse::<AttributePairs>()? {
|
for (key, value) in input.parse::<AttributePairs>()? {
|
||||||
match key.as_str() {
|
match key.as_str() {
|
||||||
"BANDWIDTH" => bandwidth = Some(value.parse::<u64>()?),
|
"BANDWIDTH" => bandwidth = Some(value.parse::<u64>().map_err(Error::parse_int)?),
|
||||||
"AVERAGE-BANDWIDTH" => average_bandwidth = Some(value.parse::<u64>()?),
|
"AVERAGE-BANDWIDTH" => {
|
||||||
|
average_bandwidth = Some(value.parse::<u64>().map_err(Error::parse_int)?)
|
||||||
|
}
|
||||||
"CODECS" => codecs = Some(unquote(value)),
|
"CODECS" => codecs = Some(unquote(value)),
|
||||||
"RESOLUTION" => resolution = Some(value.parse()?),
|
"RESOLUTION" => resolution = Some(value.parse()?),
|
||||||
"HDCP-LEVEL" => hdcp_level = Some(value.parse()?),
|
"HDCP-LEVEL" => {
|
||||||
|
hdcp_level = Some(value.parse::<HdcpLevel>().map_err(Error::strum)?)
|
||||||
|
}
|
||||||
"VIDEO" => video = Some(unquote(value)),
|
"VIDEO" => video = Some(unquote(value)),
|
||||||
_ => {
|
_ => {
|
||||||
// [6.3.1. General Client Responsibilities]
|
// [6.3.1. General Client Responsibilities]
|
||||||
|
|
|
@ -32,9 +32,10 @@ impl FromStr for Value {
|
||||||
|
|
||||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||||
if input.starts_with("0x") || input.starts_with("0X") {
|
if input.starts_with("0x") || input.starts_with("0X") {
|
||||||
Ok(Self::Hex(hex::decode(
|
Ok(Self::Hex(
|
||||||
input.trim_start_matches("0x").trim_start_matches("0X"),
|
hex::decode(input.trim_start_matches("0x").trim_start_matches("0X"))
|
||||||
)?))
|
.map_err(Error::hex)?,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
match input.parse() {
|
match input.parse() {
|
||||||
Ok(value) => Ok(Self::Float(value)),
|
Ok(value) => Ok(Self::Float(value)),
|
||||||
|
|
Loading…
Reference in a new issue