aboutsummaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* utilities: sanitize filenames and isolate temp operationssalmonik5 days1-48/+105
|
* yt-dlp: ignore configs and stop option injectionsalmonik5 days2-3/+16
|
* copyparty: never send the password to foreign hostssalmonik5 days4-28/+165
|
* say: do not abort if the ephemeral ack is already gonesalmonik6 days1-1/+3
|
* cron: keep scheduled audio silentsalmonik6 days3-3/+12
| | | | | | | Add a per-track silent flag. Cron already uses play_now (interrupt the current track), but play_next_locked still announced the track to the last known text channel; suppress playing and failure announcements for silent tracks, including when a cron track fails to prepare.
* say: post text as a normal message after an invisible acksalmonik6 days1-7/+15
| | | | | | Acknowledge the interaction with a zero-width ephemeral reply, delete it, then send the text through ChannelId::say so it lands as a normal channel message instead of an interaction reply.
* docker: bake espeak-ng data for Piper TTSsalmonik11 days5-9/+47
| | | | | | | | | | | espeak-rs-sys installs espeak-ng-data into the build tree and compiles that path in as the default, so the runtime image failed with 'phontab: No such file or directory'. Copy the data from the builder to /usr/share and point PIPER_ESPEAKNG_DATA_DIRECTORY there; compose overrides the host path from .env. Also trim trailing slashes from Copyparty base URLs, document that env_file changes need --force-recreate, and clean inline comments in .env.example.
* contextual play should add to the last in the queuesalmonik12 days1-8/+6
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* docker: build and run on Debian trixiesalmonik12 days4-0/+156
| | | | | | | | | | | Add a multi-stage image that compiles inside Debian trixie and runs on the same glibc/libssl/libopus, avoiding the Arch-built binary failing on Debian. The runtime image installs ffmpeg, qalc, the shared libraries, and the latest yt-dlp zipapp, and runs as uid 1000. compose.yaml mounts data/ and piper/, overrides TTS_MODEL_PATH for the container layout, and builds with host networking because the default Docker bridge DNS cannot resolve crates.io or deb.debian.org on this host.
* music: group playback commands under /musicsalmonik12 days5-31/+66
| | | | | | | | | Graduate grajcuj/skip/queue/stop/join into the /music parent and drop the top-level names. On startup, reconcile global slash commands and delete any that are no longer registered, since Discord otherwise keeps stale commands after a rename or move. Docs updated for the new command layout and queue semantics.
* music: add per-guild queue with now/next/last, skip and queuesalmonik12 days6-269/+790
| | | | | | | | | | Tracks are queued in memory per guild, defaulting to append (last). Playback auto-advances on TrackEvent::End/Error with a per-track token so manual stops and skips cannot double-advance. /music queue shows the current track followed by pending items. /stop clears the queue. Cron audio now goes through the same MusicState instead of poking the track-handle map directly.
* silence songbird udp_rx decode noisesalmonik2026-09-091-1/+6
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* record: 2x gain on mp3 encodesalmonik2026-09-091-0/+5
|
* test recorder ring semantics; extract mix_ticksalmonik2026-09-091-50/+187
|
* wire recording into voice manager, config, events, /record commandsalmonik2026-09-098-5/+158
|
* first draftsalmonik2026-09-092-0/+410
|
* /grajcuj plays video-like extensions toosalmonik2026-09-092-9/+9
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* message-contextual /grajcujsalmonik2026-09-093-13/+58
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* assistant replies to the messagesalmonik2026-09-093-4/+4
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* make /grajcuj w\ compress finally work as compressing a file and thensalmonik2026-09-094-48/+132
| | | | | | /grajcuj'ing Signed-off-by: salmonik <salmonik@tuta.io>
* feat: piper now not a subprocess, cache system for TTSsalmonik2026-09-0512-175/+762
|
* remove ` from TTS and make events use lang.rssalmonik2026-09-032-31/+108
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* fix: cosmetic changessalmonik2026-09-021-50/+47
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* fix: enable wav supportsalmonik2026-08-192-7/+38
|
* feat: leaderboadssalmonik2026-08-197-3/+523
|
* fix: clear voice_activity upon startingsalmonik2026-08-191-0/+4
| | | | this lets stale records from abrupt stopping be deleted
* fix: Various cron fixessalmonik2026-08-195-17/+73
| | | | | Not saving full URL Not using autocompletion content, just label
* feat: local TTS via piper subprocess with Google fallbacksalmonik2026-08-1813-95/+308
| | | | | | | | | | | - New src/tts.rs: centralize TTS in synthesize(config, http_client, text) Piper subprocess primary, Google Translate fallback on error/missing - TTS_MODEL_PATH/TTS_VOICE env config (defaults to pl_PL-bass-high) - Fix Unknown interaction errors: spawn play_tts_in_channel in background so voice-state TTS no longer blocks the shard event loop (3s Discord limit) - Best-effort confirmation replies in /tts to prevent error cascade - Custom on_error handler: graceful interaction-expired error handling - Comprehensive tracing logging (engine, model, duration, stderr)
* fir auto completion and send file in the response body upon grajcuj filesalmonik2026-07-316-22/+69
|
* fix: auto completion timing out before ready + fix preexisting warnssalmonik2026-07-3012-129/+333
|
* fix assistant and senatorsalmonik2026-07-135-74/+117
| | | | Signed-off-by: salmonik <salmonik@tuta.io>
* make cron follow local time zonesalmonik2026-07-101-11/+18
| | | | Signed-off-by: salmonik <raisersoft@proton.me>
* fix cron double firesalmonik2026-07-092-14/+46
| | | | Signed-off-by: salmonik <raisersoft@proton.me>
* search for mp4's toosalmonik2026-07-091-1/+5
| | | | Signed-off-by: salmonik <raisersoft@proton.me>
* truncate search resultssalmonik2026-07-083-16/+19
| | | | Signed-off-by: salmonik <raisersoft@proton.me>
* remember links during audio file completionsalmonik2026-07-083-6/+8
| | | | Signed-off-by: salmonik <raisersoft@proton.me>
* rename the project to what it should be namedsalmonik2026-07-082-4/+4
|\ | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
| * Merge pull request 'feat: add local API support for OpenAI compatible APIs' ↵salmonik2026-06-035-136/+122
| |\ | | | | | | | | | | | | | | | (#6) from dev into main Reviewed-on: https://codeberg.org/salmonik/senator-sperma/pulls/6
| | * feat: add local API support for OpenAI compatible APIssalmonik2026-06-035-136/+122
| | | | | | | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
* | | OPEN THE RUST GATESsalmonik2026-07-0884-6659/+11991
|/ / | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
* | Merge pull request 'Voice related fixes, alongside simplifying assistant' ↵salmonik2026-05-2120-688/+532
|\| | | | | | | | | | | (#5) from dev into main Reviewed-on: https://codeberg.org/salmonik/senator-sperma/pulls/5
| * Fix voice reconnect race: reuse VoiceClient instead of destroying itsalmonik2026-05-211-11/+43
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The stale-connection path was calling _remove_voice_client() then creating a brand-new VoiceClient via channel.connect(). This created a race: VOICE_SERVER_UPDATE (triggered by Discord when the user joins voice) arrives between the destroy and the fresh-connect, gets consumed by the old client, and the new client never receives it — causing a 10s timeout waiting for got_both_voice_updates. Fix: after disconnect(), call vc.connect() on the same VoiceClient instance. The disconnect resets the state machine to 'disconnected' but the same VoiceConnectionState processes any events that arrive between disconnect and reconnect, so the state machine correctly reaches got_both_voice_updates.
| * make the assistant simplersalmonik2026-05-211-90/+21
| | | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
| * requirements shenaniganssalmonik2026-05-215-93/+61
| | | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
| * reqs and test fixsalmonik2026-05-213-14/+16
| | | | | | | | Signed-off-by: salmonik <raisersoft@proton.me>
| * Fix zombie voice client after gateway restartsalmonik2026-05-201-1/+1
| | | | | | | | | | | | | | - play_tts: run is_voice_client_alive() check regardless of is_playing() state. After a gateway restart, is_playing() can return True on a dead client, which previously bypassed the stale-detection guard (was: 'if is_connected and not is_playing')
| * Fix stale-connection reconnect hang and TTS temp-file collisionsalmonik2026-05-202-5/+27
| | | | | | | | | | | | | | | | | | | | - _ensure_voice_client: call _remove_voice_client() when cleaning up stale or disconnected clients so the fresh connect doesn't hang for 30s waiting for Discord's stale state to clear - Reduce connect timeout from 30s to 10s for faster failure recovery - vclogs.py: use a unique temp filename per TTS call (include timestamp) instead of relying on PID alone, preventing concurrent TTS calls from clobbering each other's files
| * Redirect play_commands imports to cogs.voice, remove audio_playback shimsalmonik2026-05-203-23/+14
| | | | | | | | | | | | | | | | - Update play_commands.py to import get_voice_manager from cogs.voice instead of going through the audio_playback.py re-export shim - Delete the audio_playback.py shim file entirely - Update test_music_audio.py imports to use cogs.voice.VoiceManager - Delete PLAN_VOICE_REFACTOR.md (plan is complete)
| * Clean up consumers: replace polling with VoiceManager.play_source()salmonik2026-05-208-39/+47
| | | | | | | | | | | | | | | | | | - cron.py: replace while-is_playing polling with VoiceManager.play_source() - vclogs.py: replace while-is_playing polling with VoiceManager.play_source() - stop.py: use VoiceManager.disconnect() instead of raw voice_client - join.py: use VoiceManager.connect() instead of raw channel.connect() - voice.py: add back join_by_channel_id() convenience method - Tests: update for new VoiceManager method names and signatures
| * Fix TTS and AI voice playback bugssalmonik2026-05-202-12/+11
| | | | | | | | | | | | | | | | - tts.py _handle_voice_output: add missing voice_client.play() call via VoiceManager.play_source() — was creating the audio source and then doing nothing - ai.py: use VoiceManager.play_source() instead of passing an FFmpegPCMAudio object to play() which expects a string path