Hopefully fix some hang situations
parent
3deb9be06f
commit
71750ce584
|
@ -41,6 +41,91 @@ pub fn run(ctx: Context, command: ApplicationCommandInteraction) -> CommandOutpu
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check for Voice Channel permissions
|
||||||
|
{
|
||||||
|
let channel = match ctx.cache.guild_channel(channel_id) {
|
||||||
|
Some(channel) => channel,
|
||||||
|
None => {
|
||||||
|
respond_message(
|
||||||
|
&ctx,
|
||||||
|
&command,
|
||||||
|
EmbedBuilder::new()
|
||||||
|
.title("Cannot join voice channel")
|
||||||
|
.description("The voice channel you are in is not available")
|
||||||
|
.status(Status::Error)
|
||||||
|
.build(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(permissions) =
|
||||||
|
channel.permissions_for_user(&ctx.cache, &ctx.cache.current_user_id())
|
||||||
|
{
|
||||||
|
if !permissions.view_channel() || !permissions.connect() || !permissions.speak() {
|
||||||
|
respond_message(
|
||||||
|
&ctx,
|
||||||
|
&command,
|
||||||
|
EmbedBuilder::new()
|
||||||
|
.title("Cannot join voice channel")
|
||||||
|
.description("I do not have the permissions to connect to that voice channel")
|
||||||
|
.status(Status::Error)
|
||||||
|
.build(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for Text Channel permissions
|
||||||
|
{
|
||||||
|
let channel = match ctx.cache.guild_channel(&command.channel_id) {
|
||||||
|
Some(channel) => channel,
|
||||||
|
None => {
|
||||||
|
respond_message(
|
||||||
|
&ctx,
|
||||||
|
&command,
|
||||||
|
EmbedBuilder::new()
|
||||||
|
.title("Cannot join voice channel")
|
||||||
|
.description("The text channel you are in is not available")
|
||||||
|
.status(Status::Error)
|
||||||
|
.build(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(permissions) =
|
||||||
|
channel.permissions_for_user(&ctx.cache, &ctx.cache.current_user_id())
|
||||||
|
{
|
||||||
|
if !permissions.view_channel() || !permissions.send_messages() || !permissions.embed_links()
|
||||||
|
{
|
||||||
|
respond_message(
|
||||||
|
&ctx,
|
||||||
|
&command,
|
||||||
|
EmbedBuilder::new()
|
||||||
|
.title("Cannot join voice channel")
|
||||||
|
.description("I do not have the permissions to speak in this text channel")
|
||||||
|
.status(Status::Error)
|
||||||
|
.build(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let data = ctx.data.read().await;
|
let data = ctx.data.read().await;
|
||||||
let mut session_manager = data.get::<SessionManager>().unwrap().clone();
|
let mut session_manager = data.get::<SessionManager>().unwrap().clone();
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,6 @@ impl Client {
|
||||||
.map_err(IpcError::Bincode)
|
.map_err(IpcError::Bincode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv(&self) -> Result<IpcPacket, IpcError> {
|
|
||||||
self.rx.lock().unwrap().recv()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_recv(&self) -> Result<IpcPacket, TryRecvError> {
|
pub fn try_recv(&self) -> Result<IpcPacket, TryRecvError> {
|
||||||
self.rx.lock().unwrap().try_recv()
|
self.rx.lock().unwrap().try_recv()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use ipc_channel::ipc::{IpcError, TryRecvError};
|
||||||
use librespot::{
|
use librespot::{
|
||||||
connect::spirc::Spirc,
|
connect::spirc::Spirc,
|
||||||
core::{
|
core::{
|
||||||
|
@ -11,7 +14,7 @@ use librespot::{
|
||||||
player::{Player, PlayerEvent},
|
player::{Player, PlayerEvent},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use log::{debug, error, trace, warn};
|
use log::{debug, error, warn};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -56,8 +59,6 @@ impl SpoticordPlayer {
|
||||||
session.shutdown();
|
session.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!("Creating Spotify session...");
|
|
||||||
|
|
||||||
// Connect the session
|
// Connect the session
|
||||||
let (session, _) = match Session::connect(session_config, credentials, None, false).await {
|
let (session, _) = match Session::connect(session_config, credentials, None, false).await {
|
||||||
Ok((session, credentials)) => (session, credentials),
|
Ok((session, credentials)) => (session, credentials),
|
||||||
|
@ -106,8 +107,6 @@ impl SpoticordPlayer {
|
||||||
let device_id = session.device_id().to_owned();
|
let device_id = session.device_id().to_owned();
|
||||||
let ipc = self.client.clone();
|
let ipc = self.client.clone();
|
||||||
|
|
||||||
trace!("Successfully created Spotify session");
|
|
||||||
|
|
||||||
// IPC Handler
|
// IPC Handler
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
@ -129,8 +128,6 @@ impl SpoticordPlayer {
|
||||||
if resp.status() == 202 {
|
if resp.status() == 202 {
|
||||||
debug!("Successfully switched to device");
|
debug!("Successfully switched to device");
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
trace!("Device switch failed with status {}", resp.status());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retries -= 1;
|
retries -= 1;
|
||||||
|
@ -219,7 +216,7 @@ impl SpoticordPlayer {
|
||||||
});
|
});
|
||||||
|
|
||||||
self.spirc = Some(spirc);
|
self.spirc = Some(spirc);
|
||||||
session.spawn(spirc_task);
|
tokio::spawn(spirc_task);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(&mut self) {
|
pub fn stop(&mut self) {
|
||||||
|
@ -242,9 +239,21 @@ pub async fn main() {
|
||||||
let mut player = SpoticordPlayer::create(client.clone());
|
let mut player = SpoticordPlayer::create(client.clone());
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let message = match client.recv() {
|
let message = match client.try_recv() {
|
||||||
Ok(message) => message,
|
Ok(message) => message,
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
|
if let TryRecvError::Empty = why {
|
||||||
|
// No message, wait a bit and try again
|
||||||
|
tokio::time::sleep(Duration::from_millis(25)).await;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if let TryRecvError::IpcError(why) = &why {
|
||||||
|
if let IpcError::Disconnected = why {
|
||||||
|
debug!("IPC connection closed, goodbye");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
error!("Failed to receive message: {}", why);
|
error!("Failed to receive message: {}", why);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,7 @@ impl SpoticordSession {
|
||||||
continue;
|
continue;
|
||||||
} else if let TryRecvError::IpcError(why) = &why {
|
} else if let TryRecvError::IpcError(why) = &why {
|
||||||
if let IpcError::Disconnected = why {
|
if let IpcError::Disconnected = why {
|
||||||
|
trace!("IPC connection closed, exiting IPC handler");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,15 +458,25 @@ impl SpoticordSession {
|
||||||
|
|
||||||
/// Called when the player must stop, but not leave the call
|
/// Called when the player must stop, but not leave the call
|
||||||
async fn player_stopped(&mut self) {
|
async fn player_stopped(&mut self) {
|
||||||
if let Err(why) = self.track.pause() {
|
|
||||||
error!("Failed to pause track: {:?}", why);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect from Spotify
|
// Disconnect from Spotify
|
||||||
if let Err(why) = self.client.send(IpcPacket::Disconnect) {
|
if let Err(why) = self.client.send(IpcPacket::Disconnect) {
|
||||||
error!("Failed to send disconnect packet: {:?}", why);
|
error!("Failed to send disconnect packet: {:?}", why);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* So this is really annoying, but necessary.
|
||||||
|
* If we pause songbird too quickly, the player would still have
|
||||||
|
* some audio to write to stdout. Because songbird is paused,
|
||||||
|
* the audio is never read, and the player process will hang.
|
||||||
|
*
|
||||||
|
* So yeah we just blatanly wait a second, and hope that's enough.
|
||||||
|
* Most likely causes issues when the system is a bit slow.
|
||||||
|
*/
|
||||||
|
tokio::time::sleep(Duration::from_millis(1000)).await;
|
||||||
|
|
||||||
|
if let Err(why) = self.track.pause() {
|
||||||
|
error!("Failed to pause track: {:?}", why);
|
||||||
|
}
|
||||||
|
|
||||||
// Clear owner
|
// Clear owner
|
||||||
let mut owner = self.owner.write().await;
|
let mut owner = self.owner.write().await;
|
||||||
if let Some(owner_id) = owner.take() {
|
if let Some(owner_id) = owner.take() {
|
||||||
|
|
|
@ -68,6 +68,7 @@ pub async fn get_username(token: impl Into<String>) -> Result<String, String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
|
error!("Failed to get username: {}", response.status());
|
||||||
return Err(
|
return Err(
|
||||||
format!(
|
format!(
|
||||||
"Failed to get track info: Invalid status code: {}",
|
"Failed to get track info: Invalid status code: {}",
|
||||||
|
|
Loading…
Reference in New Issue