1use std::collections::VecDeque;
4
5use chrono::Utc;
6use m3u8_rs::{MediaPlaylist, MediaSegment};
7
8pub struct HLSConfig {
10 pub segments_to_keep: usize,
12 pub segment_duration: f32,
14 pub uri: String,
17 pub file_extension: String,
19}
20
21pub struct Playlist {
23 pub media_sequence: u64,
25 pub segments: VecDeque<MediaSegment>,
26 pub config: HLSConfig,
27}
28
29impl Playlist {
30 pub fn new(config: HLSConfig) -> Self {
32 Self {
33 media_sequence: 0,
34 segments: VecDeque::new(),
35 config,
36 }
37 }
38
39 pub fn add_segment(&mut self) -> (String, Option<String>) {
43 let removed_segment_name = if self.segments.len() >= self.config.segments_to_keep {
44 self.media_sequence += 1;
45 Some(
46 self.segments
47 .pop_front()
48 .expect("Could not remove a segment. Should never happen because if the previous if statement.")
49 .uri
50 .split('/')
51 .nth(3)
52 .expect("Could not get the segment name from its URI")
53 .to_string(),
54 )
55 } else {
56 None
57 };
58
59 let timestamp = Utc::now().timestamp_millis();
60
61 let added_segment_name =
62 String::from("segment-") + ×tamp.to_string() + &self.config.file_extension;
63
64 let uri = self.config.uri.to_owned() + &added_segment_name;
65
66 let segment = MediaSegment {
67 uri,
68 duration: self.config.segment_duration,
69 title: None,
70 byte_range: None,
71 discontinuity: false,
72 key: None,
73 map: None,
74 program_date_time: None,
75 daterange: None,
76 unknown_tags: Vec::new(),
77 };
78 self.segments.push_back(segment);
79
80 (added_segment_name, removed_segment_name)
81 }
82
83 pub fn generate_playlist(&mut self) -> Vec<u8> {
85 let playlist = MediaPlaylist {
86 version: Some(3),
87 target_duration: self.config.segment_duration.ceil(),
88 media_sequence: self.media_sequence,
89 segments: self.segments.clone().into(),
90 discontinuity_sequence: 0,
91 end_list: false,
92 playlist_type: None,
93 i_frames_only: false,
94 start: None,
95 independent_segments: false,
96 unknown_tags: Vec::new(),
97 };
98
99 let mut generated_playlist = Vec::new();
100
101 generated_playlist.clear();
102 playlist.write_to(&mut generated_playlist).unwrap();
103
104 generated_playlist
105 }
106}