add: simple play

This commit is contained in:
ParrotXray 2025-11-20 21:08:16 +08:00
parent 9225553e8d
commit f07ee239b7
Signed by: ParrotXray
SSH Key Fingerprint: SHA256:OEnKoo72UOfrmZ3LVSBn9K/UfpEzNrl+q8JMLG9CaAI
6 changed files with 130 additions and 8 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

27
.gitignore vendored
View File

@ -1 +1,28 @@
/target
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
build
target
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.next
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

1
Cargo.lock generated
View File

@ -277,6 +277,7 @@ dependencies = [
"poise",
"regex",
"serde",
"serde_json",
"serenity",
"songbird",
"tokio",

View File

@ -31,4 +31,5 @@ lavalink-rs = { version = "0.14.2", features = ["tungstenite-rustls-webpki-roots
# other
anyhow = "1.0.100"
serde = { version = "1.0.228", features = ["derive"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.145"

View File

@ -11,5 +11,6 @@ pub fn commands() -> Vec<poise::Command<BotData, Error>> {
vec![
commands::ping::ping(),
commands::music::join(),
commands::music::play(),
]
}

View File

@ -39,13 +39,6 @@ async fn _join(
match handler {
Ok((connection_info, _)) => {
lava_client
// The turbofish here is Optional, but it helps to figure out what type to
// provide in `PlayerContext::data()`
//
// While a tuple is used here as an example, you are free to use a custom
// public structure with whatever data you wish.
// This custom data is also present in the Client if you wish to have the
// shared data be more global, rather than centralized to each player.
.create_player_context_with_data::<(ChannelId, std::sync::Arc<Http>)>(
guild_id,
connection_info,
@ -82,5 +75,103 @@ pub async fn join(
_join(&ctx, guild_id, channel_id).await?;
Ok(())
}
#[poise::command(slash_command)]
pub async fn play(
ctx: Context<'_>,
#[description = "Search term or URL"]
#[rest]
term: Option<String>,
) -> Result<(), Error> {
let guild_id = ctx.guild_id().unwrap();
let has_joined = _join(&ctx, guild_id, None).await?;
let lava_client = ctx.data().lavalink.clone();
let Some(player) = lava_client.get_player_context(guild_id) else {
ctx.say("Join the bot to a voice channel first.").await?;
return Ok(());
};
let query = if let Some(term) = term {
if term.starts_with("http") {
term
} else {
//SearchEngines::YouTube.to_query(&term)?
SearchEngines::YouTube.to_query(&term)?
}
} else {
if let Ok(player_data) = player.get_player().await {
let queue = player.get_queue();
if player_data.track.is_none() && queue.get_track(0).await.is_ok_and(|x| x.is_some()) {
player.skip()?;
} else {
ctx.say("The queue is empty.").await?;
}
}
return Ok(());
};
let loaded_tracks = lava_client.load_tracks(guild_id, &query).await?;
let mut playlist_info = None;
let mut tracks: Vec<TrackInQueue> = match loaded_tracks.data {
Some(TrackLoadData::Track(x)) => vec![x.into()],
Some(TrackLoadData::Search(x)) => vec![x[0].clone().into()],
Some(TrackLoadData::Playlist(x)) => {
playlist_info = Some(x.info);
x.tracks.iter().map(|x| x.clone().into()).collect()
}
_ => {
ctx.say(format!("{:?}", loaded_tracks)).await?;
return Ok(());
}
};
if let Some(info) = playlist_info {
ctx.say(format!("Added playlist to queue: {}", info.name,))
.await?;
} else {
let track = &tracks[0].track;
if let Some(uri) = &track.info.uri {
ctx.say(format!(
"Added to queue: [{} - {}](<{}>)",
track.info.author, track.info.title, uri
))
.await?;
} else {
ctx.say(format!(
"Added to queue: {} - {}",
track.info.author, track.info.title
))
.await?;
}
}
for i in &mut tracks {
i.track.user_data = Some(serde_json::json!({"requester_id": ctx.author().id.get()}));
}
let queue = player.get_queue();
queue.append(tracks.into())?;
if has_joined {
return Ok(());
}
if let Ok(player_data) = player.get_player().await {
if player_data.track.is_none() && queue.get_track(0).await.is_ok_and(|x| x.is_some()) {
player.skip()?;
}
}
Ok(())
}