aboutsummaryrefslogtreecommitdiff
path: root/src/commands/playback/types.rs
diff options
context:
space:
mode:
authorNathan Perry <avaglir@gmail.com>2019-02-15 22:59:40 -0500
committerNathan Perry <avaglir@gmail.com>2019-02-15 22:59:40 -0500
commit61042c26faee164b51dda27561c9b67b34af8d9a (patch)
tree8d7cd258aab586c723a0690d95b5d0ed2bb88a56 /src/commands/playback/types.rs
parent6ad374d089d917cba53a76a40f9fb9bc5793ceb2 (diff)
initial implementation of video start/end times
Diffstat (limited to 'src/commands/playback/types.rs')
-rw-r--r--src/commands/playback/types.rs121
1 files changed, 119 insertions, 2 deletions
diff --git a/src/commands/playback/types.rs b/src/commands/playback/types.rs
index 63479fd..380ee9d 100644
--- a/src/commands/playback/types.rs
+++ b/src/commands/playback/types.rs
@@ -5,12 +5,13 @@ use std::{
time::Duration,
};
+use chrono::Duration as CDuration;
use either::{Either, Left, Right};
use serenity::{
client::bridge::voice::ClientVoiceManager,
model::id::ChannelId,
prelude::*,
- voice::{LockedAudio, ytdl},
+ voice::{LockedAudio},
};
use typemap::Key;
@@ -41,6 +42,8 @@ pub struct PlayArgs {
pub data: Either<String, Vec<u8>>,
pub initiator: String,
pub sender_channel: ChannelId,
+ pub start: Option<CDuration>,
+ pub end: Option<CDuration>,
}
#[derive(Clone)]
@@ -119,7 +122,7 @@ impl PlayQueue {
let src = match item.data {
Left(ref url) => {
- match ytdl(url) {
+ match ytdl(url, item.start, item.end) {
Ok(src) => src,
Err(e) => {
error!("bad link: {}; {:?}", url, e);
@@ -160,3 +163,117 @@ impl PlayQueue {
});
}
}
+
+use std::{
+ io::{
+ Read,
+ Result as IoResult,
+ BufReader,
+ },
+ process::{
+ Command,
+ Stdio,
+ Child,
+ }
+};
+
+use serenity::{
+ voice::{
+ AudioSource,
+ pcm,
+ }
+};
+use serde_json::Value;
+use crate::Result;
+
+struct ChildContainer(Child);
+
+impl Read for ChildContainer {
+ fn read(&mut self, buffer: &mut [u8]) -> IoResult<usize> {
+ self.0.stdout.as_mut().unwrap().read(buffer)
+ }
+}
+
+impl Drop for ChildContainer {
+ fn drop (&mut self) {
+ if let Err(e) = self.0.kill() {
+ debug!("[Voice] Error awaiting child process: {:?}", e);
+ }
+ }
+}
+
+
+// Copied from serenity
+pub fn ytdl(uri: &str, start: Option<CDuration>, end: Option<CDuration>) -> Result<Box<AudioSource>> {
+ let args = [
+ "-f",
+ "webm[abr>0]/bestaudio/best",
+ "--no-playlist",
+ "--print-json",
+ "--skip-download",
+ uri,
+ ];
+
+ let out = Command::new("youtube-dl")
+ .args(&args)
+ .stdin(Stdio::null())
+ .output()?;
+
+ if !out.status.success() {
+ return Err(VoiceError::YouTubeDLRun(out).into());
+ }
+
+ let value = serde_json::from_reader(&out.stdout[..])?;
+ let mut obj = match value {
+ Value::Object(obj) => obj,
+ other => return Err(VoiceError::YouTubeDLProcessing(other).into()),
+ };
+
+ let uri = match obj.remove("url") {
+ Some(v) => match v {
+ Value::String(uri) => uri,
+ other => return Err(VoiceError::YouTubeDLUrl(other).into()),
+ },
+ None => return Err(VoiceError::YouTubeDLUrl(Value::Object(obj)).into()),
+ };
+
+ let start = start.unwrap_or(CDuration::zero());
+ let start_str = format!("{:02}:{:02}:{:02}", start.num_hours(), start.num_minutes() % 60, start.num_seconds() % 60);
+
+ let mut opts = vec! [
+ "-f",
+ "s16le",
+ "-ac",
+ "2", // force stereo -- this may cause issues
+ "-ar",
+ "48000",
+ "-acodec",
+ "pcm_s16le",
+ "-ss",
+ &start_str,
+ ]
+ .into_iter()
+ .map(|s| s.to_owned())
+ .collect::<Vec<_>>();
+
+ match end {
+ Some(e) => {
+ opts.push("-to".to_owned());
+ opts.push(format!("{:02}:{:02}:{:02}", e.num_hours(), e.num_minutes() % 60, e.num_seconds() % 60));
+ },
+ _ => {},
+ }
+
+ opts.push("-".to_owned());
+
+ let command = Command::new("ffmpeg")
+ .arg("-i")
+ .arg(uri)
+ .args(opts)
+ .stderr(Stdio::null())
+ .stdin(Stdio::null())
+ .stdout(Stdio::piped())
+ .spawn()?;
+
+ Ok(pcm(true, ChildContainer(command)))
+}