use crate::{
common::misc::discord::custom::CustomDiscordPresenceManager,
linux::session::{CurrentSession, LastClipInfo, UserSessionInfo},
};
use discord_rich_presence::{
DiscordIpc, DiscordIpcClient,
activity::{Activity, ActivityType, Assets, Button, Timestamps},
};
use std::sync::mpsc;
pub mod custom;
const WAYCLIP_DISCORD_CLIENT_ID: &str = "1416659610416316466";
#[derive(Clone, Debug)]
enum PresenceCommand {
RecordingEvent { current_session: CurrentSession },
SavingEvent { current_session: CurrentSession },
}
#[derive(Clone)]
pub enum DiscordPresenceState {
Custom(CustomDiscordPresenceManager),
Default,
}
pub struct DiscordPresenceManager {
tx: mpsc::Sender<PresenceCommand>,
}
impl DiscordPresenceManager {
fn set_activity(client: &mut Option<DiscordIpcClient>, activity: Activity) {
if client.is_none() {
let mut c = DiscordIpcClient::new(WAYCLIP_DISCORD_CLIENT_ID);
match c.connect() {
Ok(()) => {
log::debug!("Connected to Discord IPC");
*client = Some(c);
}
Err(e) => {
log::debug!("Discord not available: {e}");
return;
}
}
}
let set_activity_failed = if let Some(discord) = client.as_mut() {
discord.set_activity(activity).is_err()
} else {
true
};
if set_activity_failed {
log::warn!("Failed to set Discord activity");
*client = None;
}
}
fn get_saved_buttons(last_clip_info: Option<LastClipInfo>) -> Vec<Button<'static>> {
let mut buttons = Vec::new();
if let Some(clip_info) = last_clip_info
&& let Some(url) = clip_info.url
{
buttons.push(Button::new(clip_info.name, url.to_string()));
}
buttons
}
fn get_recording_buttons(
promo_enabled: bool,
user_session_info: Option<UserSessionInfo>,
) -> Vec<Button<'static>> {
let mut buttons = Vec::new();
if promo_enabled {
buttons.push(
Button::new("Get Wayclip", "https://wayclip.com"),
);
}
if let Some(user_session) = user_session_info {
buttons.push(Button::new(
format!("{}'s profile", user_session.username),
user_session.url.to_string(),
));
}
buttons
}
pub fn new(state: DiscordPresenceState) -> Self {
let (tx, rx) = mpsc::channel::<PresenceCommand>();
let state_clone = state.clone();
std::thread::Builder::new()
.name("discord-presence".into())
.spawn(move || {
let mut client: Option<DiscordIpcClient> = None;
for command in rx {
let activity = match command {
PresenceCommand::RecordingEvent { current_session } => match state_clone {
DiscordPresenceState::Default => {
let mut activity = Activity::new().state("Recording Desktop");
if let Some(g) = current_session.game.clone() {
let mut assets = Assets::new();
if let Some(icon) = g.icon_url.clone() {
assets = assets
.large_image(icon)
.small_image("wayclip-logo")
.large_text(g.name.clone())
.small_text("Clipping with Wayclip")
}
activity = activity
.assets(assets)
.name(g.name)
.state("Clipping with Wayclip");
}
activity = activity
.activity_type(ActivityType::Playing)
.buttons(Self::get_recording_buttons(
true,
current_session.user_session,
))
.timestamps(
Timestamps::new()
.start(current_session.started_at.timestamp()),
);
activity
}
DiscordPresenceState::Custom(ref custom_config) => {
custom_config.get_activity(¤t_session)
}
},
PresenceCommand::SavingEvent { current_session } => match state_clone {
DiscordPresenceState::Default => Activity::new()
.state("Saved clip")
.details("Just saved a new clip using Wayclip!")
.activity_type(ActivityType::Playing)
.buttons(Self::get_saved_buttons(current_session.last_clip)),
DiscordPresenceState::Custom(ref custom_config) => {
custom_config.get_activity(¤t_session)
}
},
};
Self::set_activity(&mut client, activity);
}
if let Some(mut c) = client.take() {
let _ = c.close();
}
})
.expect("spawn discord thread");
Self { tx }
}
pub fn set_recording(&self, current_session: CurrentSession) {
let _ = self
.tx
.send(PresenceCommand::RecordingEvent { current_session });
}
pub fn set_saving(&self, current_session: CurrentSession) {
let _ = self
.tx
.send(PresenceCommand::SavingEvent { current_session });
}
}