initial commit
This commit is contained in:
72
src/client.rs
Normal file
72
src/client.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use anyhow::Result;
|
||||
use serenity::{
|
||||
client::Client as DiscordClient, framework::standard::StandardFramework, prelude::TypeMapKey,
|
||||
};
|
||||
use songbird::SerenityInit;
|
||||
use sunk::Client as SubsonicClient;
|
||||
|
||||
use std::{env, fs, io};
|
||||
|
||||
use crate::discord::{Handler, GENERAL_GROUP};
|
||||
|
||||
pub struct Client {
|
||||
ss_url: String,
|
||||
ss_user: String,
|
||||
ss_password: String,
|
||||
discord_token: String,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub async fn from_env() -> Result<Self> {
|
||||
// Convert to std::io::Error, allowing usage of and_then
|
||||
let convert_err = |e| io::Error::new(io::ErrorKind::Other, e);
|
||||
|
||||
let ss_url = env::var("SUBSONIC_URL")?;
|
||||
let ss_user = env::var("SUBSONIC_USER")?;
|
||||
let ss_password = env::var("SUBSONIC_PASSWORD").or_else(|_| {
|
||||
env::var("SUBSONIC_PASSWORD_FILE")
|
||||
.map_err(convert_err)
|
||||
.and_then(fs::read_to_string)
|
||||
.map(|s| s.trim().to_owned())
|
||||
})?;
|
||||
let discord_token = env::var("DISCORD_TOKEN").or_else(|_| {
|
||||
env::var("DISCORD_TOKEN_FILE")
|
||||
.map_err(convert_err)
|
||||
.and_then(fs::read_to_string)
|
||||
.map(|s| s.trim().to_owned())
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
ss_url,
|
||||
ss_user,
|
||||
ss_password,
|
||||
discord_token,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn discord(&self, ss: SubsonicClient) -> Result<DiscordClient> {
|
||||
Ok(DiscordClient::builder(&self.discord_token)
|
||||
.event_handler(Handler)
|
||||
.framework(
|
||||
StandardFramework::new()
|
||||
.configure(|c| c.prefix("~"))
|
||||
.group(&GENERAL_GROUP),
|
||||
)
|
||||
.type_map_insert::<MusicClient>(ss)
|
||||
.register_songbird()
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn subsonic(&self) -> Result<SubsonicClient> {
|
||||
Ok(SubsonicClient::new(
|
||||
&self.ss_url,
|
||||
&self.ss_user,
|
||||
&self.ss_password,
|
||||
)?)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MusicClient;
|
||||
impl TypeMapKey for MusicClient {
|
||||
type Value = SubsonicClient;
|
||||
}
|
||||
95
src/discord/mod.rs
Normal file
95
src/discord/mod.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
use serenity::{
|
||||
async_trait,
|
||||
client::{Context, EventHandler},
|
||||
framework::standard::{
|
||||
macros::{command, group},
|
||||
Args, CommandResult,
|
||||
},
|
||||
model::channel::Message,
|
||||
utils::MessageBuilder,
|
||||
};
|
||||
use sunk::{
|
||||
search::{self, SearchPage},
|
||||
Streamable,
|
||||
};
|
||||
|
||||
use crate::MusicClient;
|
||||
|
||||
#[group]
|
||||
#[commands(play)]
|
||||
pub struct General;
|
||||
|
||||
pub struct Handler;
|
||||
|
||||
#[async_trait]
|
||||
impl EventHandler for Handler {}
|
||||
|
||||
#[command]
|
||||
#[only_in(guilds)]
|
||||
#[aliases(p, queue, song)]
|
||||
#[example("~play Down Under")]
|
||||
#[description("Tocar uma música")]
|
||||
async fn play(ctx: &Context, msg: &Message, args: Args) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
|
||||
let music_client = data
|
||||
.get::<MusicClient>()
|
||||
.expect("Couldn't retrieve music client");
|
||||
|
||||
let search_size = SearchPage::new().with_size(1);
|
||||
let ignore = search::NONE;
|
||||
|
||||
let result = music_client
|
||||
.search(args.rest(), ignore, ignore, search_size)
|
||||
.await?
|
||||
.songs;
|
||||
|
||||
match result.first() {
|
||||
Some(song) => {
|
||||
let guild = msg.guild(&ctx.cache).await.unwrap();
|
||||
let guild_id = guild.id;
|
||||
|
||||
let caller_channel = guild
|
||||
.voice_states
|
||||
.get(&msg.author.id)
|
||||
.and_then(|voice_state| voice_state.channel_id);
|
||||
|
||||
let connect_to = match caller_channel {
|
||||
Some(channel) => channel,
|
||||
None => {
|
||||
msg.reply(ctx, "Você não está em um canal de voz").await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let manager = songbird::get(ctx).await.unwrap();
|
||||
let handler = manager.join(guild_id, connect_to).await;
|
||||
let mut channel_handler = handler.0.lock().await;
|
||||
|
||||
let url = song.stream_url(&music_client)?;
|
||||
let input = songbird::ffmpeg(url).await.unwrap();
|
||||
|
||||
channel_handler.play_only_source(input);
|
||||
|
||||
let message = MessageBuilder::new()
|
||||
.push("Agora tocando ")
|
||||
.push_bold_safe(format!(
|
||||
"{} - {} ({})",
|
||||
song.artist.clone().unwrap_or_default(),
|
||||
song.title,
|
||||
song.album.clone().unwrap_or_default(),
|
||||
))
|
||||
.build();
|
||||
|
||||
msg.channel_id.say(&ctx.http, &message).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
msg.channel_id
|
||||
.say(&ctx.http, "Nenhuma música encontrada")
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod client;
|
||||
pub use client::{MusicClient, Client};
|
||||
|
||||
pub mod discord;
|
||||
16
src/main.rs
Normal file
16
src/main.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use disconic::Client;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
dotenv::dotenv().ok();
|
||||
|
||||
let client = Client::from_env().await?;
|
||||
let subsonic = client.subsonic().await?;
|
||||
let mut discord = client.discord(subsonic).await?;
|
||||
|
||||
discord.start().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user