mirror of
https://github.com/narrrl/ytd-rs.git
synced 2026-11-04 00:47:02 +01:00
feat: add direct binary streaming for audio bots and media applications
This commit is contained in:
1 parent
c9872ccfbc
commit
9cffe2162a
2 files changed
+69
No files matched your search
@@ -86,5 +86,36 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Discord Bots / Media Streaming (Direct Binary Stream)
|
||||||
|
If you are building an application like a Discord bot, you often want to stream the raw binary audio data chunk-by-chunk to an engine like `ffmpeg` or `songbird` instead of downloading the whole file first.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use ytd_rs::YtDlp;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mut stream = YtDlp::new("https://www.youtube.com/watch?v=uTO0KnDsVH0")
|
||||||
|
.best_audio()
|
||||||
|
.download_to_stream()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut buffer = [0; 1024];
|
||||||
|
loop {
|
||||||
|
let bytes_read = stream.stdout().read(&mut buffer).await?;
|
||||||
|
if bytes_read == 0 { break; } // EOF
|
||||||
|
|
||||||
|
// Process your raw chunk of audio data here
|
||||||
|
// e.g., send it to your bot's audio engine
|
||||||
|
// send_to_audio_engine(&buffer[..bytes_read]);
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.wait().await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative for Discord Bots:** You can also use `.get_info().await?` to extract the direct media URL (`infos[0].url`) and pass that directly to your audio engine, which saves bot bandwidth!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
MIT
|
MIT
|
||||||
+38
@@ -93,6 +93,30 @@ impl YtDlpChild {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A running yt-dlp process that streams raw media bytes directly to standard output.
|
||||||
|
pub struct YtDlpStream {
|
||||||
|
child: tokio::process::Child,
|
||||||
|
stdout: tokio::process::ChildStdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl YtDlpStream {
|
||||||
|
/// Returns a mutable reference to the standard output to read bytes.
|
||||||
|
/// You can use this with `tokio::io::AsyncReadExt` methods like `read_buf`.
|
||||||
|
pub fn stdout(&mut self) -> &mut tokio::process::ChildStdout {
|
||||||
|
&mut self.stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Waits for the process to complete and checks its status.
|
||||||
|
pub async fn wait(mut self) -> Result<()> {
|
||||||
|
let status = self.child.wait().await?;
|
||||||
|
if status.success() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(YtDlpError::Failure("Process failed".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The main builder for configuring and running yt-dlp.
|
/// The main builder for configuring and running yt-dlp.
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct YtDlp {
|
pub struct YtDlp {
|
||||||
@@ -288,6 +312,20 @@ impl YtDlp {
|
|||||||
Ok(YtDlpChild { child, stdout })
|
Ok(YtDlpChild { child, stdout })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes yt-dlp and streams the raw media binary data to standard output.
|
||||||
|
/// This automatically sets `--output -` and gives you access to the async stdout reader.
|
||||||
|
pub async fn download_to_stream(&self) -> Result<YtDlpStream> {
|
||||||
|
let mut clone = self.clone();
|
||||||
|
clone = clone.arg_with("--output", "-");
|
||||||
|
let mut child = clone.spawn_yt_dlp(false).await?;
|
||||||
|
|
||||||
|
let stdout = child.stdout.take().ok_or_else(|| {
|
||||||
|
YtDlpError::Failure("Failed to capture standard output".to_string())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(YtDlpStream { child, stdout })
|
||||||
|
}
|
||||||
|
|
||||||
/// Executes yt-dlp with --dump-json and parses the output into VideoInfo.
|
/// Executes yt-dlp with --dump-json and parses the output into VideoInfo.
|
||||||
pub async fn get_info(&self) -> Result<Vec<VideoInfo>> {
|
pub async fn get_info(&self) -> Result<Vec<VideoInfo>> {
|
||||||
let output = self.spawn_yt_dlp(true).await?.wait_with_output().await?;
|
let output = self.spawn_yt_dlp(true).await?.wait_with_output().await?;
|
||||||
|
|||||||
Reference in new issue
Block a user