USAGE.md, CHEATSHEET.md, and TASKS.md updated to reflect enhanced
!help output that pastes detailed docstrings via FlaskPaste.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- USAGE.md: music discovery (!similar, !tags), autoplay discovery
config, Mumble admin (!mu) command reference
- CHEATSHEET.md: music discovery and Mumble admin quick reference
- ROADMAP.md: mark v2.4.0 as done, add MB fallback + !mu + autoplay
- TODO.md: mark music discovery and performance items as done
- PROJECT.md: update plugin categories table
- TASKS.md: close open doc items
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move TTS greeting from mumble._play_greet to voice.on_connected
(fires once on first connect, gated on _is_audio_ready)
- Add initial_prompt multipart field to Whisper STT for trigger word
bias (auto-generated from trigger config, overridable)
- Enhanced !queue: elapsed/total on now-playing, per-track durations,
footer with track count and total time
- New !playlist command: save/load/list/del named playlists via
bot.state persistence (playlist:<name> keys)
- Fix duck floor test (1% -> 2% to match default change)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- _cleanup_track: never delete files from kept directory (data/music/)
even when track.keep=False -- fixes kept files vanishing on replay
- !kept rm: skip to next track if removing the currently playing one
- !skip: silent (no reply), restarts play loop for autoplay on empty queue
- TTS plays through merlin's own connection instead of derp's, preventing
choppy audio when music and TTS compete for the same output buffer
- !play recognizes bare YouTube video IDs (11-char alphanumeric)
- !kept rm <id> subcommand for removing individual kept tracks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Music:
- #random URL fragment shuffles playlist tracks before enqueuing
- Lazy playlist resolution: first 10 tracks resolve immediately,
remaining are fetched in a background task
- !kept repair re-downloads kept tracks with missing local files
- !kept shows [MISSING] marker for tracks without local files
- TTS ducking: music ducks when merlin speaks via voice peer,
smooth restore after TTS finishes
Performance (from profiling):
- Connection pool: preload_content=True for SOCKS connection reuse
- Pool tuning: 30 pools / 8 connections (up from 20/4)
- _PooledResponse wrapper for stdlib-compatible read interface
- Iterative _extract_videos (replace 51K-deep recursion with stack)
- proxy=False for local SearXNG
Voice + multi-bot:
- Per-bot voice config lookup ([<username>.voice] in TOML)
- Mute detection: skip duck silence when all users muted
- Autoplay shuffle deck (no repeats until full cycle)
- Seek clamp to track duration (prevent seek-past-end stall)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Shell scripts for build, start, stop, restart, nuke, logs, status.
Shared helpers in _common.sh (colours, compose detection, project root).
Updated CHEATSHEET.md with new tool references.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add fade_step parameter to stream_audio for fast volume ramps
- _fade_and_cancel helper: smooth ~0.8s fade before track switch
- !skip, !stop, !seek now fade out instead of cutting instantly
- !prev command: go back to previous track (10-track history stack)
- !keep fetches title/artist/duration via yt-dlp, stores in bot.state
- !kept displays metadata (title, artist, duration, file size)
- !kept clear also removes stored metadata
- 29 new tests for fade, prev, history, keep metadata
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auto-resume: save playback position on stream errors and cancellation,
restore automatically after reconnect or container restart once the
channel is silent. Plugin lifecycle hook (on_connected) ensures the
reconnect watcher starts without waiting for user commands.
Sorcerer tier: new permission level between oper and admin. Configured
via [mumble] sorcerers list in derp.toml.
Mumble cert auth: pass certfile/keyfile to pymumble for client
certificate authentication.
Fixes: stream_audio now re-raises CancelledError and Exception so
_play_loop detects failures correctly. Subprocess cleanup uses 3s
timeout. Graceful shutdown cancels background tasks before stopping
pymumble. Safe getattr for _opers in core plugin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tracks playback position via frame counting in stream_audio().
On stop/skip, saves URL + elapsed time to bot.state (SQLite).
!resume reloads the track and seeks to the saved position via
ffmpeg -ss. State persists across bot restarts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Non-URL input (e.g. !play classical music) searches YouTube for 10
results and picks one randomly. Also fixes --flat-playlist returning
"NA" as the URL for single videos by falling back to the original
input URL.
Volume changes now ramp linearly per-sample via _scale_pcm_ramp instead
of jumping abruptly. Each frame steps _cur_vol toward target by at most
0.1, giving ~200ms for a full 0-to-1 sweep. Fast path unchanged when
volume is stable.
stream_audio now accepts a callable for volume, re-read on each PCM
frame instead of capturing a static float at track start.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `proxy` config option to server (IRC), teams, telegram, and mumble
sections. IRC defaults to false (preserving current direct-connect
behavior); all others default to true. The `derp.http` module now
accepts `proxy=True/False` on urlopen, create_connection,
open_connection, and build_opener -- when false, uses stdlib directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- USAGE.md: Teams Integration section (config, setup, compat matrix)
- CHEATSHEET.md: Teams config snippet
- API.md: TeamsBot and TeamsMessage reference
- README.md: Teams in features list
- ROADMAP.md: v2.1.0 milestone
- TODO.md/TASKS.md: Teams items
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- USAGE.md: permission tiers section, webhook config/API/example
- CHEATSHEET.md: ACL tiers and webhook quick-ref sections
- ROADMAP.md: mark webhook and ACL items done
- TODO.md: mark webhook and ACL items done
- TASKS.md: new sprint for ACL + webhook work
Add !cron section to USAGE.md and CHEATSHEET.md.
Mark cron, URL shortener, CI complete in ROADMAP.md and TODO.md.
New sprint in TASKS.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add cmd_paste to flaskpaste plugin (create paste, return URL).
Add test suites for encode, hash, defang, cidr, and dns plugins
(83 new test cases, 1093 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
canary: generate realistic fake credentials (token/aws/basic) for
planting as canary tripwires. Per-channel state persistence.
tcping: TCP connect latency probe through SOCKS5 proxy with
min/avg/max reporting. Proxy-compatible alternative to traceroute.
archive: save URLs to Wayback Machine via Save Page Now API,
routed through SOCKS5 proxy.
resolve: bulk DNS resolution (up to 10 hosts) via TCP DNS through
SOCKS5 proxy with concurrent asyncio.gather.
83 new tests (1010 total), docs updated.
Free, keyless API returning open ports, hostnames, CPEs, tags, and
known CVEs for any public IP. All requests routed through SOCKS5.
21 test cases (927 total).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- PoW-authenticated paste creation and URL shortening via FlaskPaste
- !paste <text> creates a paste, !shorten <url> shortens a URL
- Module-level shorten_url/create_paste helpers for cross-plugin use
- Alert plugin auto-shortens URLs in announcements and history output
- Custom TLS CA cert support via secrets/flaskpaste/derp.crt
- No SOCKS proxy -- direct urllib.request to FlaskPaste instance
v2.0.0 sprint 1 -- five standalone plugins requiring no core changes:
- jwt: decode JWT header/payload, flag alg=none/expired/nbf issues
- mac: IEEE OUI vendor lookup, random MAC generation, OUI download
- abuseipdb: IP reputation check + abuse reporting (admin) via API
- virustotal: hash/IP/domain/URL lookup via VT APIv3, 4/min rate limit
- emailcheck: SMTP RCPT TO verification via MX + SOCKS proxy (admin)
Also adds update_oui() to update-data.sh and documents all five
plugins in USAGE.md and CHEATSHEET.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Wikipedia, Stack Exchange, GitLab, npm, PyPI, Docker Hub,
arXiv, Lobsters, DEV.to, Medium, and Hugging Face backends to
the alert plugin (16 -> 27 total). Fix PyPI backend to use RSS
updates feed (web search now requires JS challenge). Fix DEV.to
to use public articles API (feed_content endpoint returns empty).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each alert result gets a deterministic 8-char base36 ID derived from
backend:item_id. IDs appear in announcements and history, and can be
looked up with !alert info <id> for full details. Existing rows are
backfilled on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hacker News (hn) uses Algolia search_by_date API for stories,
appends point count to title, falls back to HN discussion URL
when no external link. GitHub (gh) searches repositories sorted
by recently updated, shows star count and truncated description.
Both routed through SOCKS5 proxy via _urlopen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bluesky (bs) searches public post API, constructs bsky.app URLs
from at:// URIs. Lemmy (ly) queries 4 instances (lemmy.ml,
lemmy.world, programming.dev, infosec.pub) with cross-instance
dedup. Odysee (od) uses LBRY JSON-RPC claim_search for video,
audio, and documents with lbry:// to odysee.com URL conversion.
Archive.org (ia) searches via advanced search API sorted by date.
All routed through SOCKS5 proxy via _urlopen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Kick (kk) searches channels and livestreams via public search API.
Dailymotion (dm) queries video API sorted by recent. PeerTube (pt)
searches across 4 federated instances with per-instance timeout.
All routed through SOCKS5 proxy via _urlopen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DuckDuckGo (dg) searches via HTML lite endpoint with HTMLParser,
resolves DDG redirect URLs to actual targets. Google News (gn)
queries public RSS feed, parses RFC 822 dates. Both routed through
SOCKS5 proxy via _urlopen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Search Reddit posts (rd) via JSON API and Mastodon hashtag
timelines (ft) across 4 fediverse instances. Both public,
no auth required.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the bot accepts an admin INVITE, the channel is stored in
bot.state under chanmgmt/autojoin:<channel>. On reconnect, persisted
channels are rejoined alongside configured ones. If the bot is kicked,
the channel is removed from the auto-rejoin list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Matched results were announced then discarded. Add a dedicated SQLite
database (data/alert_history.db) to store every announced result with
channel, alert name, backend, title, URL, date, and timestamp. Add
!alert history <name> [n] subcommand to query recent results.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared DNS wire-format helpers into src/derp/dns.py so both
the UDP plugin (dns.py) and the new TCP plugin (tdns.py) share the
same encode/decode/build/parse logic.
The !tdns command routes queries through the SOCKS5 proxy via
derp.http.open_connection, using TCP framing (2-byte length prefix).
Default server: 1.1.1.1.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add standalone !searx command for on-demand SearXNG search (top 3 results).
Add SearX as a third backend (sx) to the alert plugin for keyword monitoring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add !username section to USAGE.md with examples. Add OSINT quick
reference entries to CHEATSHEET.md. Mark username plugin done in
ROADMAP.md and TASKS.md.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document message truncation, reconnect backoff, dork and wayback
plugins. Update roadmap, tasks, and plugin table.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>