diff options
Diffstat (limited to 'src/util.rs')
| -rw-r--r-- | src/util.rs | 111 |
1 files changed, 96 insertions, 15 deletions
diff --git a/src/util.rs b/src/util.rs index ed5fd54..d59c4da 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,3 +1,4 @@ +use chrono::Duration;
use serenity::{
client::Context,
model::{
@@ -8,32 +9,31 @@ use serenity::{ permissions::Permissions,
},
};
+use std::process::Stdio;
use lazy_static::lazy_static;
use log::debug;
-use serenity::{
- all::CreateMessage,
- futures::{
- AsyncReadExt,
- StreamExt,
- },
+use regex::{
+ Match,
+ Regex,
+};
+use serenity::all::{
+ CreateMessage,
+ Message,
};
use url::Url;
use crate::{
- audio::PlayQueue,
+ commands::songbird,
Result,
CONFIG,
};
-pub async fn currently_playing(ctx: &Context) -> bool {
- let queue_lock = {
- let data = ctx.data.read().await;
- data.get::<PlayQueue>().cloned().unwrap()
- };
+pub async fn currently_playing(ctx: &Context, msg: &Message) -> bool {
+ let (_sb, call) = songbird(ctx, msg).await.expect("no songbird");
- let play_queue = queue_lock.read().unwrap();
- play_queue.playing.is_some()
+ let call = call.lock().await;
+ call.queue().current().is_some()
}
pub async fn users_listening(ctx: &Context) -> Result<bool> {
@@ -77,7 +77,6 @@ pub async fn send_result( lazy_static! {
static ref REQUIRED_PERMS: Permissions = Permissions::EMBED_LINKS
- | Permissions::READ_MESSAGES
| Permissions::ADD_REACTIONS
| Permissions::SEND_MESSAGES
| Permissions::SEND_TTS_MESSAGES
@@ -98,3 +97,85 @@ lazy_static! { ))
.unwrap();
}
+
+pub async fn ytdl_url(uri: &str) -> Result<String> {
+ use serde_json::Value;
+ use tokio::process::Command;
+
+ lazy_static! {
+ static ref YTDL_COMMAND: String = {
+ let result = CONFIG.ytdl.clone().unwrap_or("youtube-dl".to_owned());
+ log::debug!("got ytdl: {}", result);
+
+ result
+ };
+ }
+
+ let args = [
+ "-f",
+ "webm[abr>0]/bestaudio/best",
+ "--no-playlist",
+ "--print-json",
+ "--skip-download",
+ uri,
+ ];
+
+ let out = Command::new(&*YTDL_COMMAND).args(&args).stdin(Stdio::null()).output().await?;
+
+ if !out.status.success() {
+ return Err(anyhow::anyhow!("running ytdl: {out:?}"));
+ }
+
+ let value = serde_json::from_reader(&out.stdout[..])?;
+ let mut obj = match value {
+ Value::Object(obj) => obj,
+ other => return Err(anyhow::anyhow!("ytdl output not object: {other:?}")),
+ };
+
+ match obj.remove("url") {
+ Some(v) => match v {
+ Value::String(uri) => Ok(uri),
+ other => Err(anyhow::anyhow!("url not string: {other:?}")),
+ },
+ None => Err(anyhow::anyhow!("no url")),
+ }
+}
+pub fn parse_times<A: AsRef<str>>(s: A) -> (Option<Duration>, Option<Duration>) {
+ lazy_static! {
+ static ref START_REGEX: Regex =
+ Regex::new(r"(?:start|begin(?:ning)?)\s*=?\s*(?:(?P<hours>\d+)h\s?)?(?:(?P<minutes>\d+)m\s?)?(?:(?P<seconds>\d+)s?)?").unwrap();
+
+ static ref DUR_REGEX: Regex =
+ Regex::new(r"dur(?:ation)?\s*=?\s*(?:(?P<hours>\d+)h\s?)?(?:(?P<minutes>\d+)m\s?)?(?:(?P<seconds>\d+)s?)?").unwrap();
+
+ static ref END_REGEX: Regex =
+ Regex::new(r"(?:end|term(?:inate|ination)?)\s*=?\s*(?:(?P<hours>\d+)h\s?)?(?:(?P<minutes>\d+)m\s?)?(?:(?P<seconds>\d+)s?)?").unwrap();
+ }
+
+ fn parse_match(m: Option<Match>) -> u64 {
+ m.and_then(|s| s.as_str().parse::<u64>().ok()).unwrap_or(0)
+ }
+
+ fn parse_captures<B: AsRef<str>>(r: &Regex, s: B) -> Option<Duration> {
+ r.captures(s.as_ref()).map(|capt| {
+ let hours = parse_match(capt.name("hours"));
+ let minutes = parse_match(capt.name("minutes"));
+ let seconds = parse_match(capt.name("seconds"));
+
+ let result = Duration::hours(hours as i64)
+ + Duration::minutes(minutes as i64)
+ + Duration::seconds(seconds as i64);
+
+ assert!(result >= Duration::zero());
+
+ result
+ })
+ }
+
+ let start_time = parse_captures(&START_REGEX, &s);
+ let dur = parse_captures(&DUR_REGEX, &s);
+ let end_time = parse_captures(&END_REGEX, s)
+ .or_else(|| start_time.and_then(|start| dur.map(|d| start + d)));
+
+ (start_time, end_time)
+}
|
