pub struct PlaylistDownloader { /* private fields */ }Expand description
A downloader for HLS and DASH playlist streams.
PlaylistDownloader allows configuring the download behavior (threads, retries, filters, etc.),
parsing the manifest, fetching segments concurrently, decrypting, and muxing the output files.
Implementations§
Source§impl PlaylistDownloader
impl PlaylistDownloader
Sourcepub fn new(client: &Client) -> Self
pub fn new(client: &Client) -> Self
Creates a new PlaylistDownloader with defaults.
Examples found in repository?
45async fn main() -> Result<()> {
46 let client = Client::new();
47
48 // We use ./target as temporary directory for downloaded files.
49 let dl = PlaylistDownloader::new(&client).directory("target");
50 let config = dl.get_config();
51
52 let mp = dl
53 .parse(
54 "https://media.axprod.net/TestVectors/Dash/not_protected_dash_1080p_h264/manifest.mpd",
55 false,
56 )
57 .await?;
58
59 // You can clone this token and call .cancel() to pause a download.
60 let token = CancellationToken::new();
61 let mut muxer = Muxer::new();
62
63 // Download first subtitle stream.
64 for stream in mp.streams {
65 if stream.media_type == MediaType::Subtitles {
66 println!(
67 "Downloading {} subtitles",
68 stream.language.as_deref().unwrap_or("unknown")
69 );
70
71 // We download to a temporary file, mux it in, and then clean up.
72 // You could also just move the file after download and avoid muxing if you want.
73 let dl_info = match stream.download(config, Arc::new(Progress), &token).await {
74 Ok(info) => info,
75 Err(Error::MissingSegments) => {
76 println!("Stream has no segments");
77 continue;
78 }
79 Err(Error::UnsupportedEncryption(e)) => {
80 println!("Unsupported encryption {}", e);
81 continue;
82 }
83 Err(Error::MissingKey(key_id)) => {
84 println!("Missing decryption key for {key_id}");
85 continue;
86 }
87 Err(Error::DownloadInterrupted) => {
88 println!("Download paused");
89 std::process::exit(0);
90 }
91 Err(e) => return Err(e),
92 };
93
94 println!("Downloaded {}", dl_info.path.to_string_lossy());
95 muxer.push(dl_info);
96
97 break;
98 }
99 }
100
101 println!("Muxing to target/output.srt");
102 muxer
103 .mux(&vsd::find_ffmpeg().unwrap(), "target/output.srt", "srt")
104 .await?;
105 muxer.clean(config.directory.as_deref()).await?;
106
107 Ok(())
108}Sourcepub fn base_url(self, base_url: impl Into<Url>) -> Self
pub fn base_url(self, base_url: impl Into<Url>) -> Self
Sets the base URL for resolving relative links.
Sourcepub fn clip(self, clip: &str) -> Result<Self>
pub fn clip(self, clip: &str) -> Result<Self>
Sets the clip range to download a subset of the playlist (e.g. 01:00-01:30).
§Errors
Returns an error if the clip range string is invalid.
Sourcepub fn decrypt(self, decrypt: bool) -> Self
pub fn decrypt(self, decrypt: bool) -> Self
Sets whether to attempt decrypting the streams (default: true).
Sourcepub fn directory(self, directory: impl Into<PathBuf>) -> Self
pub fn directory(self, directory: impl Into<PathBuf>) -> Self
Sets the temporary download directory (default: .).
Examples found in repository?
45async fn main() -> Result<()> {
46 let client = Client::new();
47
48 // We use ./target as temporary directory for downloaded files.
49 let dl = PlaylistDownloader::new(&client).directory("target");
50 let config = dl.get_config();
51
52 let mp = dl
53 .parse(
54 "https://media.axprod.net/TestVectors/Dash/not_protected_dash_1080p_h264/manifest.mpd",
55 false,
56 )
57 .await?;
58
59 // You can clone this token and call .cancel() to pause a download.
60 let token = CancellationToken::new();
61 let mut muxer = Muxer::new();
62
63 // Download first subtitle stream.
64 for stream in mp.streams {
65 if stream.media_type == MediaType::Subtitles {
66 println!(
67 "Downloading {} subtitles",
68 stream.language.as_deref().unwrap_or("unknown")
69 );
70
71 // We download to a temporary file, mux it in, and then clean up.
72 // You could also just move the file after download and avoid muxing if you want.
73 let dl_info = match stream.download(config, Arc::new(Progress), &token).await {
74 Ok(info) => info,
75 Err(Error::MissingSegments) => {
76 println!("Stream has no segments");
77 continue;
78 }
79 Err(Error::UnsupportedEncryption(e)) => {
80 println!("Unsupported encryption {}", e);
81 continue;
82 }
83 Err(Error::MissingKey(key_id)) => {
84 println!("Missing decryption key for {key_id}");
85 continue;
86 }
87 Err(Error::DownloadInterrupted) => {
88 println!("Download paused");
89 std::process::exit(0);
90 }
91 Err(e) => return Err(e),
92 };
93
94 println!("Downloaded {}", dl_info.path.to_string_lossy());
95 muxer.push(dl_info);
96
97 break;
98 }
99 }
100
101 println!("Muxing to target/output.srt");
102 muxer
103 .mux(&vsd::find_ffmpeg().unwrap(), "target/output.srt", "srt")
104 .await?;
105 muxer.clean(config.directory.as_deref()).await?;
106
107 Ok(())
108}Sourcepub fn format(self, format: &str) -> Result<Self>
pub fn format(self, format: &str) -> Result<Self>
Sets the format expression for stream selection (default: "bv+ba+s").
§Errors
Returns an error if the format expression is invalid.
Sourcepub fn interactive(self, raw: bool) -> Self
pub fn interactive(self, raw: bool) -> Self
Configures the stream selection interface.
If raw is true, a basic text list prompt is displayed;
otherwise, a modern interactive multi-select prompt is used.
Sourcepub fn keys(self, keys: HashMap<String, String>) -> Self
pub fn keys(self, keys: HashMap<String, String>) -> Self
Sets the decryption keys (key_id hex -> key hex).
Sourcepub fn merge(self, merge: bool) -> Self
pub fn merge(self, merge: bool) -> Self
Sets whether to merge downloaded streams into a single output file (default: true).
Sourcepub fn resume(self, resume: bool) -> Self
pub fn resume(self, resume: bool) -> Self
Sets whether to resume partial downloads (default: true).
Sourcepub fn retries(self, retries: u8) -> Self
pub fn retries(self, retries: u8) -> Self
Sets the maximum retry count per segment download (default: 10).
Sourcepub fn threads(self, threads: u8) -> Self
pub fn threads(self, threads: u8) -> Self
Sets concurrent segment download thread count (default: 5, clamped between 1 and 16).
Sourcepub fn get_config(&self) -> &PlaylistDownloadConfig
pub fn get_config(&self) -> &PlaylistDownloadConfig
Gets a reference to the download configuration.
Examples found in repository?
45async fn main() -> Result<()> {
46 let client = Client::new();
47
48 // We use ./target as temporary directory for downloaded files.
49 let dl = PlaylistDownloader::new(&client).directory("target");
50 let config = dl.get_config();
51
52 let mp = dl
53 .parse(
54 "https://media.axprod.net/TestVectors/Dash/not_protected_dash_1080p_h264/manifest.mpd",
55 false,
56 )
57 .await?;
58
59 // You can clone this token and call .cancel() to pause a download.
60 let token = CancellationToken::new();
61 let mut muxer = Muxer::new();
62
63 // Download first subtitle stream.
64 for stream in mp.streams {
65 if stream.media_type == MediaType::Subtitles {
66 println!(
67 "Downloading {} subtitles",
68 stream.language.as_deref().unwrap_or("unknown")
69 );
70
71 // We download to a temporary file, mux it in, and then clean up.
72 // You could also just move the file after download and avoid muxing if you want.
73 let dl_info = match stream.download(config, Arc::new(Progress), &token).await {
74 Ok(info) => info,
75 Err(Error::MissingSegments) => {
76 println!("Stream has no segments");
77 continue;
78 }
79 Err(Error::UnsupportedEncryption(e)) => {
80 println!("Unsupported encryption {}", e);
81 continue;
82 }
83 Err(Error::MissingKey(key_id)) => {
84 println!("Missing decryption key for {key_id}");
85 continue;
86 }
87 Err(Error::DownloadInterrupted) => {
88 println!("Download paused");
89 std::process::exit(0);
90 }
91 Err(e) => return Err(e),
92 };
93
94 println!("Downloaded {}", dl_info.path.to_string_lossy());
95 muxer.push(dl_info);
96
97 break;
98 }
99 }
100
101 println!("Muxing to target/output.srt");
102 muxer
103 .mux(&vsd::find_ffmpeg().unwrap(), "target/output.srt", "srt")
104 .await?;
105 muxer.clean(config.directory.as_deref()).await?;
106
107 Ok(())
108}Sourcepub async fn parse(
&self,
uri: &str,
partial_parse: bool,
) -> Result<MasterPlaylist>
pub async fn parse( &self, uri: &str, partial_parse: bool, ) -> Result<MasterPlaylist>
Fetches and parses the playlist manifest.
If partial_parse is true, it applies format selection and interactive prompts
to determine which streams should be processed.
§Errors
Returns an error if fetching or parsing the playlist fails.
Examples found in repository?
45async fn main() -> Result<()> {
46 let client = Client::new();
47
48 // We use ./target as temporary directory for downloaded files.
49 let dl = PlaylistDownloader::new(&client).directory("target");
50 let config = dl.get_config();
51
52 let mp = dl
53 .parse(
54 "https://media.axprod.net/TestVectors/Dash/not_protected_dash_1080p_h264/manifest.mpd",
55 false,
56 )
57 .await?;
58
59 // You can clone this token and call .cancel() to pause a download.
60 let token = CancellationToken::new();
61 let mut muxer = Muxer::new();
62
63 // Download first subtitle stream.
64 for stream in mp.streams {
65 if stream.media_type == MediaType::Subtitles {
66 println!(
67 "Downloading {} subtitles",
68 stream.language.as_deref().unwrap_or("unknown")
69 );
70
71 // We download to a temporary file, mux it in, and then clean up.
72 // You could also just move the file after download and avoid muxing if you want.
73 let dl_info = match stream.download(config, Arc::new(Progress), &token).await {
74 Ok(info) => info,
75 Err(Error::MissingSegments) => {
76 println!("Stream has no segments");
77 continue;
78 }
79 Err(Error::UnsupportedEncryption(e)) => {
80 println!("Unsupported encryption {}", e);
81 continue;
82 }
83 Err(Error::MissingKey(key_id)) => {
84 println!("Missing decryption key for {key_id}");
85 continue;
86 }
87 Err(Error::DownloadInterrupted) => {
88 println!("Download paused");
89 std::process::exit(0);
90 }
91 Err(e) => return Err(e),
92 };
93
94 println!("Downloaded {}", dl_info.path.to_string_lossy());
95 muxer.push(dl_info);
96
97 break;
98 }
99 }
100
101 println!("Muxing to target/output.srt");
102 muxer
103 .mux(&vsd::find_ffmpeg().unwrap(), "target/output.srt", "srt")
104 .await?;
105 muxer.clean(config.directory.as_deref()).await?;
106
107 Ok(())
108}