Skip to content

SNIPPIK/UnTitles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

713 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌟 WatKLOK β€” High-Performance Voice Engine for Discord

Incredible bot with its own voice/audio engine, scalable architecture, multiple filters and support for 6 music platforms.

Audio quality surpasses lavalink, don't believe me? Listen for yourself!

The project is aimed at quality, not speed!!!

English | Русский

Title

License Latest release All downloads All Contributors


πŸ‘₯ Contributors

πŸ“’ Report any bugs or omissions to Issues or Discord

Invite Server


Important

⚠️ WatKLOK (UnTitles) is a complex technical project maintained exclusively by one author, SNIPPIK
Please respect the authorship and license of the project.

Tip

I recommend enabling the caching system in .env. This will allow you to play tracks even if the platform is completely blocked. However, the voice system is simply not allowed to lose audio packets, even under critical load!

Warning

If you use a proxy, keep in mind that FFmpeg does not support socks. For such tasks, there's STH
⚠️ Some functions require proper environment configuration (FFmpeg, proxy, native modules)


⚠️ Hardware Requirements | Data from Ryzen 7 5700x3D | 1 player

  • Total load for 1 layer + shard (Voice + Player)
  • CPU: ~0.1%
  • RAM: 80 MB

What causes a heavy load

  • Scheduler for 1 thread (50 UDP + RingBuffer) ~0.1% CPU
  • OggOpusParser for 1 conversion cycle ~0.5 CPU (1.2 sec)

πŸš€ Advantages (WatKLOK)

  • The most complex operations are handled by Rust via n-api, providing almost complete independence from Node.js limitations.
  • You can define the decoder mode (voip, audio, lowdelay), enable/disable VBR, enable/disable packet loss during the download phase, and also enable FEC.
  • There are strict delay limits to limit audio corruption, which can also be changed!
Click to open

πŸ¦€ Native Voice Engine (Rust Powered)

  • The core voice processing logic is moved to a native Rust module (src-rs), ensuring stability even with high event loop lag in Node.js.
  • Voice Engine: Full implementation of Voice Gateway V8. Stack: UDP + SRTP + Opus.
  • Security: Support for End-to-End Encryption (E2EE πŸ”) via the Discord DAVE protocol.
  • Timers: Cyclic systems using a timer + auto-balancing.
  • Smart Streaming: No external Opus encoders required for streamingβ€”it uses a proprietary Opus frame parsing method.
  • FFmpeg Integration: Used for flexible audio decoding and complex filtering.

🌐 Platforms and Parsing

  • Support for YouTube, Spotify, VK, Yandex-Music, SoundCloud, Deezer, and Apple (only a draft).
  • Smart Fallback: If a track is unavailable on one platform, the system will automatically find it on another.
  • Related Tracks: Automatically selects and plays similar tracks for endless listening.
  • Worker Threads: All heavy-duty search and parsing operations are moved to separate worker threads to avoid blocking the bot's main thread. - Extensibility: Modular architecture via Dynamic Handler allows you to add a new platform in minutes.

🌍 Localization and Typing

  • Languages: Full support for Russian and English (language file).
  • DX (Developer Experience): The entire project is strongly typed (TypeScript + Rust ABI), comes with a bunch of interfaces and examples.
  • Scalability: Easily add any languages ​​supported by Discord.

πŸŽ–οΈ Event Loop Blocking Resistance

Even if the main Node.js thread is hard blocked, audio continues playing without lag or distortion.

Click to open
// πŸ’£ Event Loop Blocking Test (x4)
setInterval(() => {
    const start = performance.now();
    while (performance.now() - start < 100) {}
}, 100);

Title


🎡 Audio Quality

  • Everything depends on the limitations of Discord itself. There are no encoding restrictions; you can try feeding Discord even 512 KBit audio.
  • Hot Audio Swap: Instant seamless transitions between tracks.
  • Audio Effects: Smooth fade-in/fade-out for any actions (skip, seek, pause)
  • Filters: 16+ built-in audio filters with the ability to easily add your own via the JSON config (filters.json)
  • Sync: Direct synchronization of the audio stream without distortion introduced by software filters.

Warning

Losses on the client side are impossible, if a loss occurs accidentally you will see it in the current track message
If your internet is unstable, losses will occur in any case.
It is impossible to completely eliminate packet lost due to the UDP protocol and other discord limitations.

Entire Audio Path

Click to open
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              1. REQUEST INITIATION                                  β”‚
β”‚  /play command β†’ Platform API (YouTube, SoundCloud, Yandex...) β†’ Fetch URL/ID       β”‚
β”‚                                 (REST Layer)                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          2. RESOURCE RESOLUTION (ResourceProvider)                  β”‚
β”‚  β€’ AudioCache check (if already downloaded β†’ instant return of .opus file path)     β”‚
β”‚  β€’ If not: db.api.fetchAudioLink() β†’ obtain temporary URL from platform             β”‚
β”‚  β€’ HTTPS client (with Keep-Alive and redirects) β†’ HEAD / GET stream                 β”‚
β”‚  β€’ If needed: save stream to AudioCache (background worker)                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                             3. DECODING AND PARSING                                 β”‚
β”‚  [Rust] FFmpegProcess / native OggOpusParser (if source is already Opus)            β”‚
β”‚  β€’ Chunked reading (streaming)                                                      β”‚
β”‚  β€’ Extraction of raw Opus frames (OggParser::parse_internal)                        β”‚
β”‚  β€’ Stripping Ogg container β†’ pure Opus bytes for each frame                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         4. PLAYER PREPARATION (AudioPlayer)                         β”‚
β”‚  β€’ Track queue (Queue) β†’ Track β†’ AudioResource                                      β”‚
β”‚  β€’ If filters enabled (nightcore, bassboost) β†’ applied ON Opus without PCM          β”‚
β”‚  β€’ Hot Audio Swap: instant source switching without breaking the connection         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    5. TRANSMISSION SCHEDULER (CycleManager + Balancer)              β”‚
β”‚  [Rust] tokio runtime                                                               β”‚
β”‚  β€’ Balancer groups up to 50 active connections per cycle                            β”‚
β”‚  β€’ CycleManager runs a loop with ~20 ms interval                                    β”‚
β”‚  β€’ Each cycle pulls ready Opus frames from AudioPlayer                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                          β”‚
                                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              6. TRANSPORT LAYERS (Layers)                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚  RTPLayer                                                                   β”‚    β”‚
β”‚  β”‚  β€’ Adds RTP header (SSRC, timestamp, sequence number)                       β”‚    β”‚
β”‚  β”‚  β€’ Encrypts RTP packet with DAVELayer key (or static secret_key)            β”‚    β”‚
β”‚  β”‚  β€’ Forms final UDP datagram ready for sending                               β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚                                        β”‚                                            β”‚
β”‚                                        β–Ό                                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚
β”‚  β”‚ β”‚ DAVELayer (if channel is E2EE)                                          β”‚ β”‚    β”‚
β”‚  β”‚ β”‚ β€’ Obtains keys from MLS session                                         β”‚ β”‚    β”‚
β”‚  β”‚ β”‚ β€’ Encrypts Opus frame (AES-GCM)                                         β”‚ β”‚    β”‚
β”‚  β”‚ β”‚ β€’ Fallback: up to 3 retries on encryption failure                       β”‚ β”‚    β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚
β”‚  β”‚                                    β”‚                                        β”‚    β”‚
β”‚  β”‚                                    β–Ό                                        β”‚    β”‚
β”‚  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚    β”‚
β”‚  β”‚ β”‚ UDPLayer                                                                β”‚ β”‚    β”‚
β”‚  β”‚ β”‚ β€’ Sends packet via UDP socket to Discord Voice Server                   β”‚ β”‚    β”‚
β”‚  β”‚ β”‚ β€’ Discovery Handshake (performed once per connection)                   β”‚ β”‚    β”‚
β”‚  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
                                        β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              7. RECEPTION AND STATISTICS                            β”‚
β”‚  β€’ Discord receives RTP packets, decodes Opus, plays back in the voice channel      β”‚
β”‚  β€’ WatKLOK collects WebRTC feedback: Delay, Packet Loss                             β”‚
β”‚  β€’ Logging of all stages with [RAM] and timestamps                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸŽ› Interface

  • Interactive buttons: actions depend on the player's state
  • Progress bar support with timecodes
  • Responsive UI - no need to reuse commands

πŸ“š Commands

Click to open
Command Autocomplete Arguments Description
/filter βœ… (off, push, disable) Audio filters
/play βœ… (query) Playback
/player βœ… (api, replay, stop, related) Advanced playback
/volume βœ… value Player Volume
/remove βœ… value Delete Track
/seek ❌ 00:00, int Rewind Track
/skip βœ… (back, to, next) Skip Tracks
/repeat βœ… type Repeat Type
/queue βœ… {destroy, list} Queue Management
/voice βœ… (join, leave, tribune) Voice Channel

πŸš€ Launch

  • Node.js, FFmpeg, and Rust (optional) required
  • You don't need to build Rust components! Ready-made builds here

All parameters should already be defined in .env.custom, so take it and rename it to .env

# Clone
git clone https://github.com/SNIPPIK/UnTitles
cd UnTitles

# Install dependencies
npm i

# If you need to build Rust components
# If you don't want to build, download the ready-made build and add everything to build/native
npm run build:native

# Build Typescript + run
npm run build && npm run start

πŸ“Š Project Diagram

  • In case you're curious about how the bot is built
Click to open

Diagram

About

This is the first discord music bot that breaks stereotypes about audio quality!

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors