use crate::m3u8::playlist::Playlist;
use crate::m3u8::tags::Tag;
use crate::m3u8::validation::ValidationError;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Clone)]
pub struct PlaylistBuilder {
tags: Rc<RefCell<Vec<Tag>>>,
}
impl Default for PlaylistBuilder {
fn default() -> Self {
Self::new()
}
}
impl PlaylistBuilder {
pub fn new() -> Self {
Self {
tags: Rc::new(RefCell::new(Vec::new())),
}
}
pub fn extm3u(self) -> Self {
self.tags.borrow_mut().push(Tag::ExtM3U);
self
}
pub fn version(self, version: u8) -> Self {
self.tags.borrow_mut().push(Tag::ExtXVersion(version));
self
}
pub fn extinf(self, url: &str, duration: f32, title: Option<String>) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtInf(url.to_string(), duration, title));
self
}
pub fn target_duration(self, duration: u64) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXTargetDuration(duration));
self
}
pub fn media_sequence(self, sequence: u64) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXMediaSequence(sequence));
self
}
pub fn discontinuity_sequence(self, sequence: u32) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXDiscontinuitySequence(sequence));
self
}
pub fn end_list(self) -> Self {
self.tags.borrow_mut().push(Tag::ExtXEndList);
self
}
pub fn key(
self,
method: &str,
uri: Option<&str>,
iv: Option<&str>,
keyformat: Option<&str>,
keyformatversions: Option<&str>,
) -> Self {
self.tags.borrow_mut().push(Tag::ExtXKey {
method: method.to_string(),
uri: uri.map(|s| s.to_string()),
iv: iv.map(|s| s.to_string()),
keyformat: keyformat.map(|s| s.to_string()),
keyformatversions: keyformatversions.map(|s| s.to_string()),
});
self
}
pub fn map(self, uri: &str, byterange: Option<&str>) -> Self {
self.tags.borrow_mut().push(Tag::ExtXMap {
uri: uri.to_string(),
byterange: byterange.map(|s| s.to_string()),
});
self
}
pub fn program_date_time(self, date_time: &str) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXProgramDateTime(date_time.to_string()));
self
}
pub fn gap(self) -> Self {
self.tags.borrow_mut().push(Tag::ExtXGap);
self
}
pub fn byte_range(self, byterange: &str) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXByteRange(byterange.to_string()));
self
}
pub fn define(self, value: &str) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXDefine(value.to_string()));
self
}
#[allow(clippy::too_many_arguments)]
pub fn media(
self,
type_: &str,
group_id: &str,
name: Option<&str>,
uri: Option<&str>,
default: Option<bool>,
autoplay: Option<bool>,
characteristics: Option<&str>,
language: Option<&str>,
forced: Option<bool>,
language_codec: Option<&str>,
instream_id: Option<&str>,
) -> Self {
self.tags.borrow_mut().push(Tag::ExtXMedia {
type_: type_.to_string(),
group_id: group_id.to_string(),
name: name.map(|s| s.to_string()),
uri: uri.map(|s| s.to_string()),
default,
autoplay,
characteristics: characteristics.map(|s| s.to_string()),
language: language.map(|s| s.to_string()),
instream_id: instream_id.map(|s| s.to_string()),
language_codec: language_codec.map(|s| s.to_string()),
forced,
});
self
}
#[allow(clippy::too_many_arguments)]
pub fn stream_inf(
self,
bandwidth: u32,
codecs: Option<&str>,
resolution: Option<&str>,
frame_rate: Option<f32>,
audio: Option<&str>,
video: Option<&str>,
subtitle: Option<&str>,
closed_captions: Option<&str>,
) -> Self {
self.tags.borrow_mut().push(Tag::ExtXStreamInf {
bandwidth,
codecs: codecs.map(|s| s.to_string()),
resolution: resolution.map(|s| s.to_string()),
frame_rate,
audio: audio.map(|s| s.to_string()),
video: video.map(|s| s.to_string()),
subtitle: subtitle.map(|s| s.to_string()),
closed_captions: closed_captions.map(|s| s.to_string()),
});
self
}
pub fn iframe_stream_inf(
self,
bandwidth: u32,
codecs: Option<&str>,
resolution: Option<&str>,
frame_rate: Option<f32>,
uri: &str,
) -> Self {
self.tags.borrow_mut().push(Tag::ExtXIFrameStreamInf {
bandwidth,
codecs: codecs.map(|s| s.to_string()),
resolution: resolution.map(|s| s.to_string()),
frame_rate,
uri: uri.to_string(),
});
self
}
pub fn bitrate(self, bitrate: u32) -> Self {
self.tags.borrow_mut().push(Tag::ExtXBitrate(bitrate));
self
}
pub fn independent_segments(self) -> Self {
self.tags.borrow_mut().push(Tag::ExtXIndependentSegments);
self
}
pub fn start(self, time_offset: &str, precise: Option<bool>) -> Self {
self.tags.borrow_mut().push(Tag::ExtXStart {
time_offset: time_offset.to_string(),
precise,
});
self
}
pub fn session_data(self, id: &str, value: &str, language: Option<&str>) -> Self {
self.tags.borrow_mut().push(Tag::ExtXSessionData {
id: id.to_string(),
value: value.to_string(),
language: language.map(|s| s.to_string()),
});
self
}
pub fn session_key(self, method: &str, uri: Option<&str>, iv: Option<&str>) -> Self {
self.tags.borrow_mut().push(Tag::ExtXSessionKey {
method: method.to_string(),
uri: uri.map(|s| s.to_string()),
iv: iv.map(|s| s.to_string()),
});
self
}
pub fn build(self) -> Result<Playlist, Vec<ValidationError>> {
let playlist = Playlist {
tags: self.tags.borrow().clone(),
};
match playlist.validate() {
Ok(_) => Ok(playlist),
Err(errors) => Err(errors),
}
}
pub fn playlist_type(self, playlist_type: &str) -> Self {
self.tags
.borrow_mut()
.push(Tag::ExtXPlaylistType(playlist_type.to_string()));
self
}
}