track how many sounds are playing in a channel
This commit is contained in:
parent
909e8e351a
commit
d70f790b3d
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1809,7 +1809,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "songbird"
|
name = "songbird"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "git+https://github.com/serenity-rs/songbird?branch=current#df64ad92e5dc150790be2216c4e79b6fefa4964a"
|
source = "git+https://github.com/FelixMcFelix/songbird?branch=fix-driver-leave-join#a5c4f915bc24c09460c36156a96b38e2957bceb4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"async-tungstenite 0.13.1",
|
"async-tungstenite 0.13.1",
|
||||||
@ -1838,7 +1838,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "soundfx-rs"
|
name = "soundfx-rs"
|
||||||
version = "1.2.0"
|
version = "1.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dashmap",
|
"dashmap",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "soundfx-rs"
|
name = "soundfx-rs"
|
||||||
version = "1.2.0"
|
version = "1.2.2"
|
||||||
authors = ["jellywx <judesouthworth@pm.me>"]
|
authors = ["jellywx <judesouthworth@pm.me>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ tokio = { version = "1.0", features = ["fs", "process", "io-util"] }
|
|||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
reqwest = "0.11"
|
reqwest = "0.11"
|
||||||
env_logger = "0.8"
|
env_logger = "0.8"
|
||||||
songbird = { git = "https://github.com/serenity-rs/songbird", branch = "current" }
|
songbird = { git = "https://github.com/FelixMcFelix/songbird", branch = "fix-driver-leave-join" }
|
||||||
regex = "1.4"
|
regex = "1.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
40
src/event_handlers.rs
Normal file
40
src/event_handlers.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use serenity::async_trait;
|
||||||
|
use serenity::model::id::GuildId;
|
||||||
|
use songbird::Event;
|
||||||
|
use songbird::EventContext;
|
||||||
|
use songbird::EventHandler as SongbirdEventHandler;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
pub struct RestartTrack;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl SongbirdEventHandler for RestartTrack {
|
||||||
|
async fn act(&self, ctx: &EventContext<'_>) -> Option<Event> {
|
||||||
|
if let EventContext::Track(&[(_state, track)]) = ctx {
|
||||||
|
let _ = track.seek_time(Default::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UpdateTrackCount {
|
||||||
|
pub guild_id: GuildId,
|
||||||
|
pub track_count: Arc<RwLock<HashMap<GuildId, u32>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl SongbirdEventHandler for UpdateTrackCount {
|
||||||
|
async fn act(&self, _ctx: &EventContext<'_>) -> Option<Event> {
|
||||||
|
{
|
||||||
|
let mut write_lock = self.track_count.write().await;
|
||||||
|
|
||||||
|
let current = write_lock.get(&self.guild_id).cloned();
|
||||||
|
write_lock.insert(self.guild_id, current.unwrap_or(1) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
141
src/main.rs
141
src/main.rs
@ -4,21 +4,26 @@ extern crate lazy_static;
|
|||||||
extern crate reqwest;
|
extern crate reqwest;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod event_handlers;
|
||||||
mod framework;
|
mod framework;
|
||||||
mod guild_data;
|
mod guild_data;
|
||||||
mod sound;
|
mod sound;
|
||||||
|
|
||||||
use guild_data::GuildData;
|
use crate::{
|
||||||
use sound::Sound;
|
event_handlers::{RestartTrack, UpdateTrackCount},
|
||||||
|
framework::RegexFramework,
|
||||||
|
guild_data::{CtxGuildData, GuildData},
|
||||||
|
sound::Sound,
|
||||||
|
};
|
||||||
|
|
||||||
use regex_command_attr::command;
|
use regex_command_attr::command;
|
||||||
|
|
||||||
use serenity::{
|
use serenity::{
|
||||||
async_trait,
|
|
||||||
client::{bridge::gateway::GatewayIntents, Client, Context},
|
client::{bridge::gateway::GatewayIntents, Client, Context},
|
||||||
framework::standard::{Args, CommandResult},
|
framework::standard::{Args, CommandResult},
|
||||||
http::Http,
|
http::Http,
|
||||||
model::{
|
model::{
|
||||||
|
channel::Channel,
|
||||||
channel::Message,
|
channel::Message,
|
||||||
guild::Guild,
|
guild::Guild,
|
||||||
id::{ChannelId, GuildId, RoleId},
|
id::{ChannelId, GuildId, RoleId},
|
||||||
@ -31,19 +36,17 @@ use serenity::{
|
|||||||
use songbird::{
|
use songbird::{
|
||||||
create_player,
|
create_player,
|
||||||
error::JoinResult,
|
error::JoinResult,
|
||||||
events::EventHandler as SongbirdEventHandler,
|
|
||||||
ffmpeg,
|
ffmpeg,
|
||||||
input::{cached::Memory, Input},
|
input::{cached::Memory, Input},
|
||||||
Call, Event, EventContext, SerenityInit,
|
tracks::TrackHandle,
|
||||||
|
Call, Event, SerenityInit, TrackEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
use sqlx::mysql::MySqlPool;
|
use sqlx::mysql::MySqlPool;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
|
||||||
use crate::{framework::RegexFramework, guild_data::CtxGuildData};
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use serenity::model::channel::Channel;
|
|
||||||
use std::{collections::HashMap, convert::TryFrom, env, sync::Arc, time::Duration};
|
use std::{collections::HashMap, convert::TryFrom, env, sync::Arc, time::Duration};
|
||||||
use tokio::sync::{MutexGuard, RwLock};
|
use tokio::sync::{MutexGuard, RwLock};
|
||||||
|
|
||||||
@ -71,6 +74,12 @@ impl TypeMapKey for GuildDataCache {
|
|||||||
type Value = Arc<DashMap<GuildId, Arc<RwLock<GuildData>>>>;
|
type Value = Arc<DashMap<GuildId, Arc<RwLock<GuildData>>>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct GuildTrackCount;
|
||||||
|
|
||||||
|
impl TypeMapKey for GuildTrackCount {
|
||||||
|
type Value = Arc<RwLock<HashMap<GuildId, u32>>>;
|
||||||
|
}
|
||||||
|
|
||||||
const THEME_COLOR: u32 = 0x00e0f3;
|
const THEME_COLOR: u32 = 0x00e0f3;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -150,7 +159,20 @@ impl EventHandler for Handler {
|
|||||||
if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 {
|
if channel.members(&ctx).await.map(|m| m.len()).unwrap_or(0) <= 1 {
|
||||||
let songbird = songbird::get(&ctx).await.unwrap();
|
let songbird = songbird::get(&ctx).await.unwrap();
|
||||||
|
|
||||||
let _ = songbird.remove(guild_id).await;
|
{
|
||||||
|
let track_count = ctx
|
||||||
|
.data
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get::<GuildTrackCount>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut write_lock = track_count.write().await;
|
||||||
|
write_lock.insert(guild_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = songbird.leave(guild_id).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,8 +252,7 @@ async fn play_audio(
|
|||||||
call_handler: &mut MutexGuard<'_, Call>,
|
call_handler: &mut MutexGuard<'_, Call>,
|
||||||
mysql_pool: MySqlPool,
|
mysql_pool: MySqlPool,
|
||||||
loop_: bool,
|
loop_: bool,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<TrackHandle, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
{
|
|
||||||
let (track, track_handler) =
|
let (track, track_handler) =
|
||||||
create_player(sound.store_sound_source(mysql_pool.clone()).await?.into());
|
create_player(sound.store_sound_source(mysql_pool.clone()).await?.into());
|
||||||
|
|
||||||
@ -244,12 +265,11 @@ async fn play_audio(
|
|||||||
}
|
}
|
||||||
|
|
||||||
call_handler.play(track);
|
call_handler.play(track);
|
||||||
}
|
|
||||||
|
|
||||||
sound.plays += 1;
|
sound.plays += 1;
|
||||||
sound.commit(mysql_pool).await?;
|
sound.commit(mysql_pool).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(track_handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn join_channel(
|
async fn join_channel(
|
||||||
@ -384,10 +404,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let guild_data_cache = Arc::new(DashMap::new());
|
let guild_data_cache = Arc::new(DashMap::new());
|
||||||
|
let guild_track_count = Arc::new(RwLock::new(HashMap::new()));
|
||||||
|
|
||||||
let mut data = client.data.write().await;
|
let mut data = client.data.write().await;
|
||||||
|
|
||||||
data.insert::<GuildDataCache>(guild_data_cache);
|
data.insert::<GuildDataCache>(guild_data_cache);
|
||||||
|
data.insert::<GuildTrackCount>(guild_track_count);
|
||||||
data.insert::<MySQL>(mysql_pool);
|
data.insert::<MySQL>(mysql_pool);
|
||||||
|
|
||||||
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
|
data.insert::<ReqwestClient>(Arc::new(reqwest::Client::new()));
|
||||||
@ -581,11 +603,11 @@ async fn play_cmd(ctx: &Context, msg: &Message, args: Args, loop_: bool) -> Comm
|
|||||||
let (call_handler, _) =
|
let (call_handler, _) =
|
||||||
join_channel(ctx, guild.clone(), user_channel).await;
|
join_channel(ctx, guild.clone(), user_channel).await;
|
||||||
|
|
||||||
let guild_data = ctx.guild_data(guild).await.unwrap();
|
let guild_data = ctx.guild_data(guild_id).await.unwrap();
|
||||||
|
|
||||||
let mut lock = call_handler.lock().await;
|
let mut lock = call_handler.lock().await;
|
||||||
|
|
||||||
play_audio(
|
let track_handle = play_audio(
|
||||||
sound,
|
sound,
|
||||||
guild_data.read().await.volume,
|
guild_data.read().await.volume,
|
||||||
&mut lock,
|
&mut lock,
|
||||||
@ -593,6 +615,29 @@ async fn play_cmd(ctx: &Context, msg: &Message, args: Args, loop_: bool) -> Comm
|
|||||||
loop_,
|
loop_,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
let track_count = ctx
|
||||||
|
.data
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get::<GuildTrackCount>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut write_lock = track_count.write().await;
|
||||||
|
|
||||||
|
let current = write_lock.get(&guild_id).cloned();
|
||||||
|
write_lock.insert(guild_id, current.unwrap_or(0) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = track_handle.add_event(
|
||||||
|
Event::Track(TrackEvent::End),
|
||||||
|
UpdateTrackCount {
|
||||||
|
guild_id,
|
||||||
|
track_count,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
@ -621,19 +666,6 @@ async fn play_cmd(ctx: &Context, msg: &Message, args: Args, loop_: bool) -> Comm
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RestartTrack;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl SongbirdEventHandler for RestartTrack {
|
|
||||||
async fn act(&self, ctx: &EventContext<'_>) -> Option<Event> {
|
|
||||||
if let EventContext::Track(&[(_state, track)]) = ctx {
|
|
||||||
let _ = track.seek_time(Default::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[command]
|
#[command]
|
||||||
#[permission_level(Managed)]
|
#[permission_level(Managed)]
|
||||||
async fn play_ambience(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
async fn play_ambience(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||||
@ -656,34 +688,44 @@ async fn play_ambience(ctx: &Context, msg: &Message, args: Args) -> CommandResul
|
|||||||
let audio_index = ctx.data.read().await.get::<AudioIndex>().cloned().unwrap();
|
let audio_index = ctx.data.read().await.get::<AudioIndex>().cloned().unwrap();
|
||||||
|
|
||||||
if let Some(filename) = audio_index.get(&search_name) {
|
if let Some(filename) = audio_index.get(&search_name) {
|
||||||
{
|
|
||||||
let (call_handler, _) = join_channel(ctx, guild.clone(), user_channel).await;
|
|
||||||
|
|
||||||
let guild_data = ctx.guild_data(guild).await.unwrap();
|
|
||||||
|
|
||||||
let mut lock = call_handler.lock().await;
|
|
||||||
|
|
||||||
// stop anything currently playing
|
|
||||||
lock.stop();
|
|
||||||
|
|
||||||
let (track, track_handler) = create_player(
|
let (track, track_handler) = create_player(
|
||||||
Input::try_from(
|
Input::try_from(
|
||||||
Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap())
|
Memory::new(ffmpeg(format!("audio/{}", filename)).await.unwrap()).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let (call_handler, _) = join_channel(ctx, guild.clone(), user_channel).await;
|
||||||
|
let guild_data = ctx.guild_data(guild).await.unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut lock = call_handler.lock().await;
|
||||||
|
|
||||||
|
lock.play(track);
|
||||||
|
}
|
||||||
|
|
||||||
let _ = track_handler.set_volume(guild_data.read().await.volume as f32 / 100.0);
|
let _ = track_handler.set_volume(guild_data.read().await.volume as f32 / 100.0);
|
||||||
let _ = track_handler.add_event(
|
let _ = track_handler.add_event(
|
||||||
Event::Periodic(
|
Event::Periodic(
|
||||||
track_handler.metadata().duration.unwrap() - Duration::from_millis(500),
|
track_handler.metadata().duration.unwrap() - Duration::from_millis(200),
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
RestartTrack {},
|
RestartTrack {},
|
||||||
);
|
);
|
||||||
|
|
||||||
lock.play(track);
|
{
|
||||||
|
let track_count = ctx
|
||||||
|
.data
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get::<GuildTrackCount>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut write_lock = track_count.write().await;
|
||||||
|
|
||||||
|
let current = write_lock.get(&msg.guild_id.unwrap()).cloned();
|
||||||
|
write_lock.insert(msg.guild_id.unwrap(), current.unwrap_or(0) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.channel_id
|
msg.channel_id
|
||||||
@ -725,9 +767,24 @@ __Available ambience sounds:__
|
|||||||
#[command]
|
#[command]
|
||||||
#[permission_level(Managed)]
|
#[permission_level(Managed)]
|
||||||
async fn stop_playing(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
async fn stop_playing(ctx: &Context, msg: &Message, _args: Args) -> CommandResult {
|
||||||
|
{
|
||||||
|
let guild_id = msg.guild_id.unwrap();
|
||||||
|
|
||||||
|
let track_count = ctx
|
||||||
|
.data
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get::<GuildTrackCount>()
|
||||||
|
.cloned()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut write_lock = track_count.write().await;
|
||||||
|
write_lock.insert(guild_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
let voice_manager = songbird::get(ctx).await.unwrap();
|
let voice_manager = songbird::get(ctx).await.unwrap();
|
||||||
|
|
||||||
let _ = voice_manager.remove(msg.guild_id.unwrap()).await;
|
let _ = voice_manager.leave(msg.guild_id.unwrap()).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user