aboutsummaryrefslogtreecommitdiffstats
path: root/src/tasks
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-19 02:45:49 +0200
committersalmonik <salmonik@tuta.io>2026-08-19 02:45:49 +0200
commit850fad62f12b4e764f5e64036db35259237994cb (patch)
treed5b25e9c00f01e3fd19f47b0270a88e1e5f5576e /src/tasks
parentfeat: local TTS via piper subprocess with Google fallback (diff)
downloadsenator-sperma-850fad62f12b4e764f5e64036db35259237994cb.tar.gz
senator-sperma-850fad62f12b4e764f5e64036db35259237994cb.zip
fix: Various cron fixes
Not saving full URL Not using autocompletion content, just label
Diffstat (limited to 'src/tasks')
-rw-r--r--src/tasks/mod.rs37
1 files changed, 30 insertions, 7 deletions
diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs
index 4408857..d4cf9b2 100644
--- a/src/tasks/mod.rs
+++ b/src/tasks/mod.rs
@@ -1,3 +1,4 @@
1use std::collections::HashMap;
1use std::sync::Arc; 2use std::sync::Arc;
2 3
3use chrono::{DateTime, Duration, Local, TimeZone, Timelike, Utc}; 4use chrono::{DateTime, Duration, Local, TimeZone, Timelike, Utc};
@@ -18,6 +19,7 @@ pub struct CronContext {
18 pub http: Arc<serenity::Http>, 19 pub http: Arc<serenity::Http>,
19 pub voice_manager: VoiceManager, 20 pub voice_manager: VoiceManager,
20 pub copyparty: CopypartyClient, 21 pub copyparty: CopypartyClient,
22 pub music_tracks: Arc<tokio::sync::Mutex<HashMap<u64, songbird::tracks::TrackHandle>>>,
21} 23}
22 24
23/// Normalize user-friendly cron expressions to the 7-field format the `cron` crate expects. 25/// Normalize user-friendly cron expressions to the 7-field format the `cron` crate expects.
@@ -118,15 +120,25 @@ async fn execute_message_job(ctx: &CronContext, job: &crate::database::CronJob)
118} 120}
119 121
120async fn execute_audio_job(ctx: &CronContext, job: &crate::database::CronJob) { 122async fn execute_audio_job(ctx: &CronContext, job: &crate::database::CronJob) {
121 let Some(ref audio_path) = job.audio_filename else { 123 let Some(ref audio_url) = job.audio_filename else {
122 error!("Cron audio job {} has no audio_filename", job.id); 124 error!("Cron audio job {} has no audio_filename", job.id);
123 return; 125 return;
124 }; 126 };
125 127
126 let channel_id = serenity::ChannelId::new(job.channel_id as u64); 128 let channel_id = serenity::ChannelId::new(job.channel_id as u64);
127 129
128 // Resolve guild + build URL concurrently. 130 // Build the full URL with password
129 let url = ctx.copyparty.build_url(audio_path); 131 let url = if audio_url.starts_with("http://") || audio_url.starts_with("https://") {
132 // Already a full URL (stored without password), append it now
133 if let Some(pw) = &ctx.copyparty.password {
134 format!("{audio_url}?pw={pw}")
135 } else {
136 audio_url.clone()
137 }
138 } else {
139 // Legacy relative path — build full URL with password
140 ctx.copyparty.build_url(audio_url)
141 };
130 info!("Cron audio job {} streaming via ffmpeg: {url}", job.id); 142 info!("Cron audio job {} streaming via ffmpeg: {url}", job.id);
131 let guild_channel_fut = channel_id.to_channel(&ctx.http); 143 let guild_channel_fut = channel_id.to_channel(&ctx.http);
132 let input_fut = crate::voice::ffmpeg_stream_input(&url); 144 let input_fut = crate::voice::ffmpeg_stream_input(&url);
@@ -157,6 +169,14 @@ async fn execute_audio_job(ctx: &CronContext, job: &crate::database::CronJob) {
157 } 169 }
158 }; 170 };
159 171
172 // Stop any existing track in this guild.
173 {
174 let mut map = ctx.music_tracks.lock().await;
175 if let Some(handle) = map.remove(&guild_id.get()) {
176 let _ = handle.stop();
177 }
178 }
179
160 // Connect to voice and play. 180 // Connect to voice and play.
161 let call = match ctx.voice_manager.connect(guild_id, channel_id).await { 181 let call = match ctx.voice_manager.connect(guild_id, channel_id).await {
162 Ok(c) => c, 182 Ok(c) => c,
@@ -166,14 +186,17 @@ async fn execute_audio_job(ctx: &CronContext, job: &crate::database::CronJob) {
166 } 186 }
167 }; 187 };
168 188
169 { 189 let handle = {
170 let mut call_lock = call.lock().await; 190 let mut call_lock = call.lock().await;
171 call_lock.play_input(input); 191 call_lock.play_input(input)
172 } 192 };
193
194 // Store the handle so the track stays alive.
195 ctx.music_tracks.lock().await.insert(guild_id.get(), handle);
173 196
174 info!( 197 info!(
175 "Cron audio job {} playing '{}' (url: {url}) in guild {}", 198 "Cron audio job {} playing '{}' (url: {url}) in guild {}",
176 job.id, audio_path, guild_id 199 job.id, audio_url, guild_id
177 ); 200 );
178} 201}
179 202