Skip to main content

PlaylistDownloader

Struct PlaylistDownloader 

Source
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

Source

pub fn new(client: &Client) -> Self

Creates a new PlaylistDownloader with defaults.

Examples found in repository?
examples/playlist_dl.rs (line 49)
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}
Source

pub fn base_url(self, base_url: impl Into<Url>) -> Self

Sets the base URL for resolving relative links.

Source

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.

Source

pub fn decrypt(self, decrypt: bool) -> Self

Sets whether to attempt decrypting the streams (default: true).

Source

pub fn directory(self, directory: impl Into<PathBuf>) -> Self

Sets the temporary download directory (default: .).

Examples found in repository?
examples/playlist_dl.rs (line 49)
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}
Source

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.

Source

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.

Source

pub fn keys(self, keys: HashMap<String, String>) -> Self

Sets the decryption keys (key_id hex -> key hex).

Source

pub fn merge(self, merge: bool) -> Self

Sets whether to merge downloaded streams into a single output file (default: true).

Source

pub fn query(self, query: &str) -> Self

Sets query parameters to append to requests.

Source

pub fn resume(self, resume: bool) -> Self

Sets whether to resume partial downloads (default: true).

Source

pub fn retries(self, retries: u8) -> Self

Sets the maximum retry count per segment download (default: 10).

Source

pub fn threads(self, threads: u8) -> Self

Sets concurrent segment download thread count (default: 5, clamped between 1 and 16).

Source

pub fn get_config(&self) -> &PlaylistDownloadConfig

Gets a reference to the download configuration.

Examples found in repository?
examples/playlist_dl.rs (line 50)
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}
Source

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?
examples/playlist_dl.rs (lines 53-56)
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}

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more