diff options
Diffstat (limited to '')
| -rw-r--r-- | src/tasks/mod.rs | 37 |
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 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 1 | use std::sync::Arc; | 2 | use std::sync::Arc; |
| 2 | 3 | ||
| 3 | use chrono::{DateTime, Duration, Local, TimeZone, Timelike, Utc}; | 4 | use 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 | ||
| 120 | async fn execute_audio_job(ctx: &CronContext, job: &crate::database::CronJob) { | 122 | async 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 | ||
