mirror of
https://github.com/sile/hls_m3u8.git
synced 2024-12-23 12:30:29 +00:00
Rewrote Lines
This commit is contained in:
parent
3721106795
commit
273c0990dc
3 changed files with 72 additions and 78 deletions
117
src/line.rs
117
src/line.rs
|
@ -1,87 +1,74 @@
|
|||
use std::fmt;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::tags;
|
||||
use crate::types::SingleLineString;
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lines<'a> {
|
||||
input: &'a str,
|
||||
}
|
||||
impl<'a> Lines<'a> {
|
||||
pub const fn new(input: &'a str) -> Self {
|
||||
Lines { input }
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Lines(Vec<Line>);
|
||||
|
||||
impl Lines {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn read_line(&mut self) -> crate::Result<Line<'a>> {
|
||||
let mut end = self.input.len();
|
||||
let mut next_start = self.input.len();
|
||||
let mut adjust = 0;
|
||||
let mut next_line_of_ext_x_stream_inf = false;
|
||||
impl FromStr for Lines {
|
||||
type Err = Error;
|
||||
|
||||
for (i, c) in self.input.char_indices() {
|
||||
match c {
|
||||
'\n' => {
|
||||
if !next_line_of_ext_x_stream_inf
|
||||
&& self.input.starts_with(tags::ExtXStreamInf::PREFIX)
|
||||
{
|
||||
next_line_of_ext_x_stream_inf = true;
|
||||
adjust = 0;
|
||||
continue;
|
||||
}
|
||||
next_start = i + 1;
|
||||
end = i - adjust;
|
||||
break;
|
||||
}
|
||||
'\r' => {
|
||||
adjust = 1;
|
||||
}
|
||||
_ => {
|
||||
if c.is_control() {
|
||||
return Err(Error::invalid_input());
|
||||
}
|
||||
adjust = 0;
|
||||
}
|
||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||
let mut result = Lines::new();
|
||||
|
||||
for line in input.lines() {
|
||||
// ignore empty lines
|
||||
if line.trim().len() == 0 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let raw_line = &self.input[..end];
|
||||
|
||||
let line = if raw_line.is_empty() {
|
||||
Line::Blank
|
||||
} else if raw_line.starts_with("#EXT") {
|
||||
Line::Tag((raw_line.parse())?)
|
||||
} else if raw_line.starts_with('#') {
|
||||
Line::Comment(raw_line)
|
||||
} else {
|
||||
let uri = SingleLineString::new(raw_line)?;
|
||||
Line::Uri(uri)
|
||||
};
|
||||
let pline = {
|
||||
if line.starts_with("#EXT") {
|
||||
Line::Tag(line.parse()?)
|
||||
} else if line.starts_with("#") {
|
||||
continue; // ignore comments
|
||||
} else {
|
||||
Line::Uri(SingleLineString::new(line)?)
|
||||
}
|
||||
};
|
||||
|
||||
self.input = &self.input[next_start..];
|
||||
Ok(line)
|
||||
}
|
||||
}
|
||||
impl<'a> Iterator for Lines<'a> {
|
||||
type Item = crate::Result<Line<'a>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.input.is_empty() {
|
||||
return None;
|
||||
result.push(pline);
|
||||
}
|
||||
|
||||
match self.read_line() {
|
||||
Err(e) => Some(Err(e)),
|
||||
Ok(line) => Some(Ok(line)),
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Lines {
|
||||
type Item = Line;
|
||||
type IntoIter = ::std::vec::IntoIter<Line>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Lines {
|
||||
type Target = Vec<Line>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Lines {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Line<'a> {
|
||||
Blank,
|
||||
Comment(&'a str),
|
||||
pub enum Line {
|
||||
Tag(Tag),
|
||||
Uri(SingleLineString),
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::tags::{
|
|||
ExtXSessionKey, ExtXStart, ExtXStreamInf, ExtXVersion, MasterPlaylistTag,
|
||||
};
|
||||
use crate::types::{ClosedCaptions, MediaType, ProtocolVersion};
|
||||
use crate::{Error, Result};
|
||||
use crate::Error;
|
||||
|
||||
/// Master playlist builder.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -69,7 +69,7 @@ impl MasterPlaylistBuilder {
|
|||
}
|
||||
|
||||
/// Builds a `MasterPlaylist` instance.
|
||||
pub fn finish(self) -> Result<MasterPlaylist> {
|
||||
pub fn finish(self) -> crate::Result<MasterPlaylist> {
|
||||
let required_version = self.required_version();
|
||||
let specified_version = self.version.unwrap_or(required_version);
|
||||
|
||||
|
@ -116,7 +116,7 @@ impl MasterPlaylistBuilder {
|
|||
.expect("Never fails")
|
||||
}
|
||||
|
||||
fn validate_stream_inf_tags(&self) -> Result<()> {
|
||||
fn validate_stream_inf_tags(&self) -> crate::Result<()> {
|
||||
let mut has_none_closed_captions = false;
|
||||
for t in &self.stream_inf_tags {
|
||||
if let Some(group_id) = t.audio() {
|
||||
|
@ -159,7 +159,7 @@ impl MasterPlaylistBuilder {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_i_frame_stream_inf_tags(&self) -> Result<()> {
|
||||
fn validate_i_frame_stream_inf_tags(&self) -> crate::Result<()> {
|
||||
for t in &self.i_frame_stream_inf_tags {
|
||||
if let Some(group_id) = t.video() {
|
||||
if !self.check_media_group(MediaType::Video, group_id) {
|
||||
|
@ -171,7 +171,7 @@ impl MasterPlaylistBuilder {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_session_data_tags(&self) -> Result<()> {
|
||||
fn validate_session_data_tags(&self) -> crate::Result<()> {
|
||||
let mut set = HashSet::new();
|
||||
for t in &self.session_data_tags {
|
||||
if !set.insert((t.data_id(), t.language())) {
|
||||
|
@ -182,7 +182,7 @@ impl MasterPlaylistBuilder {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_session_key_tags(&self) -> Result<()> {
|
||||
fn validate_session_key_tags(&self) -> crate::Result<()> {
|
||||
let mut set = HashSet::new();
|
||||
for t in &self.session_key_tags {
|
||||
if !set.insert(t.key()) {
|
||||
|
@ -294,11 +294,11 @@ impl fmt::Display for MasterPlaylist {
|
|||
|
||||
impl FromStr for MasterPlaylist {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
|
||||
fn from_str(input: &str) -> Result<Self, Self::Err> {
|
||||
let mut builder = MasterPlaylistBuilder::new();
|
||||
for (i, line) in Lines::new(s).enumerate() {
|
||||
match (line)? {
|
||||
Line::Blank | Line::Comment(_) => {}
|
||||
for (i, line) in input.parse::<Lines>()?.into_iter().enumerate() {
|
||||
match line {
|
||||
Line::Tag(tag) => {
|
||||
if i == 0 {
|
||||
if tag != Tag::ExtM3u(ExtM3u) {
|
||||
|
@ -373,3 +373,11 @@ impl FromStr for MasterPlaylist {
|
|||
builder.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parser() {}
|
||||
}
|
||||
|
|
|
@ -337,9 +337,8 @@ impl MediaPlaylistOptions {
|
|||
let mut segment = MediaSegmentBuilder::new();
|
||||
let mut has_partial_segment = false;
|
||||
let mut has_discontinuity_tag = false;
|
||||
for (i, line) in Lines::new(m3u8).enumerate() {
|
||||
match (line)? {
|
||||
Line::Blank | Line::Comment(_) => {}
|
||||
for (i, line) in m3u8.parse::<Lines>()?.into_iter().enumerate() {
|
||||
match line {
|
||||
Line::Tag(tag) => {
|
||||
if i == 0 {
|
||||
if tag != Tag::ExtM3u(ExtM3u) {
|
||||
|
|
Loading…
Reference in a new issue