Simplified enqueue_track to parse track type (playlist or single track)

This commit is contained in:
2024-12-18 19:05:13 -05:00
parent c82fee0dd3
commit aa7bad945a
5 changed files with 144 additions and 116 deletions

View File

@@ -9,7 +9,7 @@ use songbird::{Event, EventHandler, Songbird, TrackEvent};
use crate::bot::commands::audio::leave_voice_channel;
use crate::data::guilds::GuildCache;
use crate::bot::ytdlp::{PlaylistItem, YtDlp};
use crate::bot::ytdlp::{YtDlp, YtDlpItem};
use crate::error::{SirenResult, Error as SirenError};
use crate::HttpKey;
@@ -57,12 +57,12 @@ pub async fn run(ctx: &Context, command: &CommandInteraction) {
log::debug!("<{guild_id}> Play command executed on {channel_id} with track: {track_url:?}");
// Handle the track url
match enqueue_track(ctx, manager, guild_id.to_owned(), track_url).await {
Ok(count) => {
let mut message = format!("Playing {} tracks", count);
if count == 0 {
Ok(items) => {
let mut message = format!("Added {} tracks", items.len());
if items.len() == 0 {
message = "No tracks were played".to_string();
} else if count == 1 {
message = "Playing 1 track".to_string();
} else if items.len() == 1 {
message = format!("Added **{}**", items[0].get_title());
}
edit_response(&ctx, &command, message).await;
}
@@ -84,42 +84,32 @@ pub async fn enqueue_track(
manager: Arc<Songbird>,
guild_id: GuildId,
track_url: &str,
) -> SirenResult<i32> {
let mut track_count = 0;
) -> SirenResult<Vec<YtDlpItem>> {
let mut playlist_items: Vec<YtDlpItem> = Vec::new();
if let Some(handler_lock) = manager.get(guild_id) {
let mut handler = handler_lock.lock().await;
let guild = GuildCache::get_by_id(guild_id.get() as i64).await?.unwrap();
let valid = is_valid_url(&track_url);
// Check if the URL is valid
if !valid.0 {
if !valid {
log::warn!("<{guild_id}> Invalid track url: {}", track_url);
return Err(SirenError::new(
422,
format!("Invalid track url: {}", track_url),
));
}
let mut playlist_items: Vec<PlaylistItem> = Vec::new();
// Check if the URL is a playlist or a single track
if valid.1 {
playlist_items = match get_playlist_urls(&track_url) {
Ok(items) => items,
Err(err) => {
log::warn!("<{guild_id}> Failed to get playlist urls: {}", err);
return Err(SirenError::new(422, err.to_string()));
}
};
} else {
let playlist_item = PlaylistItem {
id: "".to_string(),
url: track_url.to_string(),
title: "".to_string(),
duration: 0,
playlist_index: 0,
};
playlist_items.push(playlist_item);
}
playlist_items = match get_ytdlp_items(&track_url) {
Ok(items) => items,
Err(err) => {
log::warn!("<{guild_id}> Failed to get playlist urls: {}", err);
return Err(SirenError::new(422, err.to_string()));
}
};
// Add each track to the queue
for item in playlist_items {
for item in &playlist_items {
let volume = guild.volume as f32 / 100.0;
let http_client = {
let data = ctx.data.read().await;
@@ -128,21 +118,17 @@ pub async fn enqueue_track(
.cloned()
.expect("Guaranteed to exist in the typemap.")
};
let source = YoutubeDl::new(http_client, item.url.to_owned());
let mut input: Input = source.into();
let metadata = match input.aux_metadata().await {
Ok(metadata) => metadata,
Err(err) => {
log::warn!("<{guild_id}> Failed to get metadata for track: {err}");
let _ = leave_voice_channel(&manager, &guild_id).await;
return Err(SirenError::new(422, err.to_string()));
}
};
let source = YoutubeDl::new(http_client, item.get_url().to_owned());
let input: Input = source.into();
let track_title = item.get_title().to_owned();
let track_handle: TrackHandle;
track_handle = handler.enqueue_input(input).await;
// Set the volume
let _ = track_handle.set_volume(volume);
let track_title = metadata.title.unwrap();
log::debug!("<{guild_id}> Added track: {}", track_title);
handler.remove_all_global_events();
handler.add_global_event(
@@ -152,29 +138,28 @@ pub async fn enqueue_track(
call: manager.clone(),
},
);
track_count += 1;
}
if handler.queue().is_empty() {
let _ = handler.queue().resume();
}
}
Ok(track_count)
Ok(playlist_items)
}
pub fn get_playlist_urls(url: &str) -> SirenResult<Vec<PlaylistItem>> {
pub fn get_ytdlp_items(url: &str) -> SirenResult<Vec<YtDlpItem>> {
let output = YtDlp::new()
.arg("--flat-playlist")
.arg("--dump-json")
.arg(url)
.execute()?;
let items: Vec<PlaylistItem> = String::from_utf8(output.stdout)?
let items: Vec<YtDlpItem> = String::from_utf8(output.stdout)?
.split('\n')
.filter_map(|line| {
if line.is_empty() {
None
} else {
Some(
serde_json::from_slice::<PlaylistItem>(line.as_bytes())
serde_json::from_slice::<YtDlpItem>(line.as_bytes())
.map_err(|err| SirenError::new(500, err.to_string())),
)
}