Skip to content

v3.9.0

Latest

Choose a tag to compare

@1Lucas1apk 1Lucas1apk released this 14 Sep 22:22
cdb02c6

Helloooooooooooo WOoooorld

💚 NodeLink v3.9.0

so uh

this one got really big

NodeLink v3.9.0 is finally here, and there are 182 commits between v3.8.0 and v3.9.0. This release ended up touching pretty much every major part of NodeLink, from startup and networking to DSP, memory management, source resolution, voice, clustering, security, configuration, and the internal architecture

There is honestly a lot to talk about here, so instead of just saying that "a bunch of stuff was fixed", here is what actually changed

Startup

One of the first things we wanted to improve was startup time. NodeLink could take around 10 seconds to cold start depending on the environment, and a big part of that was the tsx layer used to execute TypeScript

That layer is now gone

NodeLink now uses native TypeScript execution from Node.js, with support across modern Node.js versions from v22.x through v26.x

The result is a cold start that can now go from around 10 seconds to under 1 second

That is a pretty massive difference for something that can be restarted frequently, especially when running multiple workers or recovering nodes. It also means NodeLink spends considerably less time just getting itself ready before it can actually serve requests

Bun

Bun also became a much bigger part of NodeLink in this release

useBunServer: true is now the default, and instead of treating Bun as just another runtime NodeLink can run on, we are making much better use of its native HTTP and WebSocket implementations

The request shims were improved as well, along with native fetch fast paths and several changes intended to reduce unnecessary allocations and networking overhead

There were also multiple fixes around Bun HTTP, fetch behavior, request shims, dependency updates, and the server structure itself

The goal here was not just "NodeLink works with Bun"

The goal was making Bun a proper first-class server path

Audio processing

This is probably where v3.9.0 got a little out of hand

We started with the base crossfade implementation and kept building on top of it until it turned into the Smart Crossfade Engine

Instead of simply fading one track out while fading another in, NodeLink can now analyze the tracks before a transition happens

It can look at BPM, harmonic key compatibility, the Camelot Wheel, and energy envelopes to determine how a transition should behave

That means the transition is no longer just based on time

It can actually take the music into account

Bass swap

One of the biggest parts of the transition system is the asymmetric multi-band bass-swap crossover

The problem with simply overlapping two tracks is that both tracks usually have their own kick, bass, and low-end energy. During a transition, those frequencies can stack together and make the result sound muddy very quickly

The bass-swap system allows NodeLink to handle the low-end differently during the transition so the outgoing and incoming tracks are not simply fighting over the same frequencies

The goal is keeping the transition powerful without turning the low end into a mess

Vocal anti-clash

There is also progressive vocal anti-clash ducking

Two songs can be harmonically compatible and still sound terrible when both vocal sections are playing at full strength at the same time

NodeLink can progressively reduce conflicting vocal content so one vocal section has room for the other instead of both competing for the same space

This is one of those features that sounds simple when written down, but becomes considerably more complicated once it has to happen continuously while the audio is being processed

Mid/Side spatial morphing

The transition system also makes use of Mid/Side processing for spatial movement

Instead of only changing volume, the stereo field can evolve as the transition progresses

This gives transitions considerably more movement and allows the sound stage to change instead of staying completely static

There are also several effects that can be combined with these transitions, including Schroeder reverb tails, vinyl tape stops, and spinbacks

And then there is Tesseract 4D

The Tesseract filter uses a 4D hypercube rotation approach for spatial DSP, which is probably one of the stranger things currently living inside NodeLink

Voice activated ducking

We also added the new DuckingController

NodeLink can now react to voice activity in Discord voice channels and smoothly lower the music while someone is speaking

When the speech stops, the music can return naturally

This means the system is not just applying a fixed volume reduction. It can react to actual voice activity and dynamically make room for speech

Equalizer performance

The Equalizer also received a pretty important optimization

There is no real reason to spend CPU processing a biquad filter when the filter is effectively doing nothing

Inactive unity-gain filters can now be bypassed completely

That means NodeLink can skip those filters instead of processing them on every audio chunk

The result was up to 56% lower chunk processing time in the tested path, while saving around 5.2ms of CPU core time per second per player

That gets especially interesting when you have many players running simultaneously

One small optimization repeated across many audio frames and many players stops being small very quickly

Memory usage

Memory was another huge focus of this release

The old Opus pipeline relied on a 512KB circular ring buffer, which has now been replaced by a zero-copy leftover frame strategy

The BufferPool bucket depth was also increased from 4 to 16

Together, those changes reached around 97% buffer reuse and reclaimed roughly 200–400MB of RAM in the tested workloads

The changes were not limited to Opus either

Scratch and tape buffers now use lazy allocation, AAC and WebM demuxer caches were tightened, finished filters and mixers are torn down immediately, and MLS key packages are also cleaned up as soon as they are no longer needed

One of the more interesting measurements came from JSArrayBufferData

With 19 active players, retained memory dropped from around 146MB to 19.5MB

That is a pretty huge difference, especially on smaller servers where memory usage matters a lot

NativeDOM

We also completely removed jsdom

It was previously used for the DOM environment required by the YouTube PoToken generation path

Instead of carrying a complete DOM implementation just for that, NodeLink now has its own lightweight NativeDOM

That removes roughly 20MB from node_modules, while also reducing CPU and memory overhead during PoToken generation and SABR streaming

The implementation is specifically designed around what NodeLink actually needs rather than trying to emulate an entire browser DOM

YouTube

YouTube streaming received another major overhaul

The stream handling is now based around bounded HTTP 206 chunking using roughly 12-second / 512KB slices

The idea is to behave more like direct browser media requests and avoid keeping large or fragile ranges open for too long

This helps with connection timeouts and also reduces a number of 416 range failures

We also added more client fallback options, including visionOs and tv_downgraded, giving NodeLink additional ways to deal with aggressive 403 and 429 responses

There were also several changes around visitorData, including fetching, initialization, fallback behavior, and the removal of problematic global caching

The player-side fallback path was improved for watch pages returning 429, and YouTube recovery and itag fallback received another pass

Basically, YouTube will keep changing things, so NodeLink needs to be able to survive those changes without the entire playback pipeline immediately falling apart

Shazam

Shazam also went through a fairly major change

The old HTML scraping approach was fragile, so resolution was moved toward direct Apple Music API handling

There were still fixes around decoy HTML and commerce fallback handling, but the important part is that resolution is no longer tied to the same fragile website structure

That should make the source considerably more resilient to page changes

More sources

There was a lot of work across sources in general

Bilibili URLs are now supported, TikTok video support was added, Newgrounds gained support and additional 403 fallback handling, Instagram direct audio playback was restored, and Instagram handling was improved for more Unicode characters

SoundCloud gained support for shortened URLs and now respects the configured clientId

Spotify gained playlist and artist searching, its search behavior now respects search.maxResults, and recommendations gained a GraphQL fallback

Deezer albums now return the correct playlist load type and stale Deezer CSRF credentials can be refreshed after failures

YouTube Music fallback resolution was fixed, TTS sources received fixes, and Qobuz support was added to monochrome

There was also a lot of general maintenance across multiple sources that does not fit neatly into a single feature name

Stream lifecycle

One of the recurring themes in this release was lifecycle management

Streams should actually disappear when they are finished, recovery should stop when a player is destroyed, event listeners should not survive the stream they belong to, and mix layers should not keep pipelines alive after teardown

There were fixes specifically targeting crossfade destruction, SABR recovery after player destruction, decoder WASM memory leaks, worker crashes during teardown, and general stream lifecycle handling

These are not always bugs that immediately show themselves

They usually appear later as memory growth, stuck players, unexpected events, or workers that mysteriously stop behaving correctly

Seeking and gapless playback

Seek handling also received several fixes

NodeLink can now reuse a seekable resource instead of unnecessarily refetching it, MP4 decoder sample rate handling was fixed, and gapless playback received fixes for its fading start position

Both the JavaScript and normal paths received the relevant gapless fixes

Track-end fade delays are now recomputed when playback speed changes, and the transition field was correctly forwarded across 12 AnimatableFilter subclasses

All of this becomes increasingly important once playback speed, animated filters, transitions, and crossfades start interacting with each other

SABR

SABR received quite a bit of work as well

Its types were reorganized, playback stability was improved, recovery behavior was fixed, stream drops and decoding failures were addressed, and several cases where recovery could continue after a player had already been destroyed were fixed

YouTube recovery and itag fallback were also improved

The overall goal was making SABR behave more like a controlled streaming pipeline instead of a collection of independent recovery mechanisms

Cluster

Cluster mode received some important architectural changes

Worker identity could become ambiguous in some situations, so NodeLink now uses an explicit IPC event socket HELLO handshake for worker identification

This prevents worker ID collisions and keeps worker and player ownership consistent

Players can also self-heal after voice reconnects, missing cluster players can be restored, and loadchapters received a fix for 500 responses in cluster mode

Update checks were also moved so that certain checks only run in the primary process instead of being repeated by every worker

Voice

Voice handling received a lot of smaller but important fixes

Voice errors can now be deferred in cases where immediately reacting to them could cause bad disconnects

Voice reconnects can recover more reliably, channel_id is passed through voice updates, and the default encryption mode is now aead_xchacha20_poly1305_rtpsize

The encryption implementation is backed by sodium-native, with a reported 300% improvement in packet encryption and decryption throughput

Security

There was also another serious security pass in this release

Local file playback received protection against path traversal, the profiler received symlink escape protection, rate-limit handling was improved, worker eviction issues were addressed, API request body hangs were fixed, and routeplanner sub-routes are now registered correctly

Duplicate stream terminal events are prevented, HEAD request handling received better error management, source proxy options became null-safe, and several fallback paths became safer

These are not necessarily the most visible changes when installing a new version, but they matter considerably more once NodeLink is exposed to real traffic

Configuration

Configuration was reorganized quite a bit

diskCacheEnabled was added, configuration migration and cache management were implemented, the configuration schema was flattened, stricter unknown typing was introduced, runtime validation was synchronized with the new structure, and the default configuration was updated to match it

YouTube visitorData and proxy management also received more robust handling

The overall result is a configuration system that should be easier to maintain and safer to evolve

Dependency updates

The dependency update system also received work

Results can now be persisted in a cache, dependency update checks are rate limited, checks can run synchronously during initialization where necessary, automatic dependency updates and restart handling were improved, and package versions were updated

Bun dependency update support was also added

There were also fixes for package etarget errors and target-version handling during auto-update, including protection against reboot loops caused by targeting the wrong package version

TypeScript and code quality

There was quite a lot of cleanup that probably will not show up in a feature list but makes a difference long term

TypeScript was bumped to version 7, many any usages were replaced with proper types, Biome formatting and checks were expanded, project-wide linting was applied, the architecture was modernized, redundant logic was removed, manual debugging instrumentation was added, and compiled files were updated

The Bun implementation was also refactored into a cleaner structure

This release is not only about adding features

A large part of it was making the code behind those features easier to maintain afterwards

Supported clients

Node.js 26 is now supported

Lavalink.lua was added to the supported clients list

General client compatibility was improved, additional parameters were included for other YouTube clients, and several client-specific fallback paths were added or corrected

Monochrome

Monochrome also received several changes

FLAC can now be preferred, a FLAC seek crash was fixed, Qobuz support was added, and monochrome is disabled by default

There were also several stream lifecycle and compatibility improvements around the system

Documentation and maintenance

There were a few smaller project-level changes too

The README and Dockerfile were updated to reflect the newer behavior, deprecated version information was removed, aesthetic support guidelines were added for multiple Discord links, and Magmastream entries were updated with version information

There were also several merge and synchronization commits keeping the development branches aligned

182 commits later

so yeah

that is basically v3.9.0

what started as another release ended up touching startup, Bun, HTTP, WebSocket, DSP, crossfade, equalizer processing, memory management, Opus, AAC, MP4, WASM, YouTube, SABR, Spotify, Deezer, Shazam, SoundCloud, Instagram, Newgrounds, TikTok, Bilibili, voice, cluster, security, configuration, dependencies, TypeScript, and a lot of internal code

there are still things to improve

there are still bugs somewhere

and there will probably be another weird YouTube problem tomorrow

but v3.9.0 is a pretty big step forward for NodeLink

and after 182 commits I think it is safe to say this one got a little bigger than expected

thanks to everyone who contributed code, reported issues, tested things, opened PRs, reviewed changes, or just kept using NodeLink

now it is finally out


Full Changelog

Commit count in v3.8.0..v3.9.0: 182

Added

• 3d073cd tropadoratomcleon-source: add: missing file

• b6f9d38 ToddyTheNoobDud: add: support for oggopus files

• fd41f1a ToddyTheNoobDud: add: support for bilibili.tv urls

• 0eb335e ToddyTheNoobDud: add: visionOs client support

• c81fa1c 1lucas1apk: add: crossfade (initial base)

• 4f11de9 1lucas1apk: add: diskCacheEnabled option to configuration

• 2ef244b 1lucas1apk: add: sequential player patching for groups

• 63bc0c1 ToddyTheNoobDud: add: new preferredSources option in lyrics

• f72cb09 1lucas1apk: add: tesseract 4d rotation dsp filter

• 8e7f947 ToddyTheNoobDud: add: newgrounds source support

• d74264a 1lucas1apk: add: ducking feature to automatically lower music volume when speaking

• 2fa8dd4 ToddyTheNoobDud: add: tv_downgraded client support

• d59014b ToddyTheNoobDud: add: ALAC codec support

• 37ee917 ToddyTheNoobDud: add: new youtube stream handling; fix: major memory leaks/memory retention

• ba3f366 ToddyTheNoobDud: add: more prefixes support

• 3cd7757 ToddyTheNoobDud: add: node 26 support

• 34daff8 ToddyTheNoobDud: add: tiktok video support

Fixed

• f61237d SreerajSK990: fix: resolve ratelimit, worker eviction, body hang, and path traversal

• e77f2f5 ToddyTheNoobDud: fix: stop worker crash when tearing down mix layers with open pipelines

• 9c6962a SreerajSK990: fix(spotify): add GraphQL fallback for recommendations

• fa0f5ac ToddyTheNoobDud: fix: connecting players being detected as dead

• 82cbda7 Akinori: fix: preserve explicit null endTime through seek pipeline

• 7ea699c ToddyTheNoobDud: fix: restore voice reconnects and self-heal missing cluster players

• 1cbb10e ToddyTheNoobDud: fix: musixmatch econnrefused

• 3294dc5 ToddyTheNoobDud: fix: detach event listeners during stream and crossfade destroy

• a825121 ToddyTheNoobDud: fix: resolve MP4 playback failures and decoder WASM memory leaks

• 3d41ad8 Akinori: fix: recompute trackEnd fade delay for playback speed changes

• 644a2c7 ToddyTheNoobDud: fix: resolve shazam decoy html via commerce fallback

• 032ae2d ToddyTheNoobDud: fix: etarget error on package update

• 5519080 Akinori: fix: apply skipMarginMs in updateSponsorBlock

• 360d574 ToddyTheNoobDud: fix: sabr recovery still happening after player destroy

• 171de77 Akinori: fix: forward transition field in 12 AnimatableFilter subclasses

• 3a81d5c ToddyTheNoobDud: fix: tts sources not working

• e905cf4 ToddyTheNoobDud: fix: player watch page 429s causing the source not to load

• 73dd9c9 ToddyTheNoobDud: fix: http errors 416 during itag switch

• fba3dba Akinori: fix: register routeplanner sub-routes correctly

• 26512a5 Shahbaz !!: fix: prevent duplicate stream terminal events

• d7283e8 Lucas Morais Rodrigues: fix: star history

• f6f526f Lucas Morais Rodrigues: fix. star history

• c0f7a9b Razi: fix: resolve audio stream, demuxer, and source bugs

• 3ed2cbd Shahbaz !!: fix: prevent profiler file symlink escapes

• 8870621 SreerajSK990: fix(youtube): resolve letterboxed hqdefault thumbnails

• d436810 1lucas1apk: fix: target package version on auto-update to prevent reboot loops

• 7693a7e ToddyTheNoobDud: fix: visitorData initializing twice

• dbc0c82 ToddyTheNoobDud: fix: player get and false stuck errors

• 98483b9 ToddyTheNoobDud: fix: android failing to search

• ae6db36 Akinori: fix: use seekable resource for seeks instead of refetching

• c703729 GDjkhp: fix: reset fading start postion for gapless (js)

• 24b417f GDjkhp: fix: reset fading start postion for gapless

• 714bb51 ToddyTheNoobDud: fix: prevent circular source fallback resolution

• 3853f63 ToddyTheNoobDud: fix: merge conflict on lyrics

• 7fee2e9 ToddyTheNoobDud: fix: preferredSources is not iterable

• ac84f69 ToddyTheNoobDud: fix: mp4 decoder sample rate issues

• 86e85be ToddyTheNoobDud: fix: make source proxy options null-safe

• cc09a76 ToddyTheNoobDud: fix: shazam failing to resolve

• f4dc20f ToddyTheNoobDud: fix: 403s errors with TV client

• 8e30535 ToddyTheNoobDud: fix: clamp search maxResults to 50 for Spotify API compatibility

• 9a56ca8 ToddyTheNoobDud: fix: return playlist loadType for deezer albums

• ec5c279 ToddyTheNoobDud: fix: refresh stale Deezer CSRF credentials on failure

• aec6fbc ToddyTheNoobDud: fix: resolve youtube music fallback not working

• 8cd02de rafael: fix(spotify): use search.maxResults configuration for search limit

• 4850878 ToddyTheNoobDud: fix: youtube tracks being stuck on connection reset while paused

• 64266c4 1Lucas1apk: fix: remove global caching of visitorData

• 2d23abf 1Lucas1apk: fix: await update checks to run synchronously during initialization

• 8ee7c94 1Lucas1apk: fix: run update checks only in primary process

• 8e66d29 ToddyTheNoobDud: fix: resolve false stuck track detection on stream end

• c4a2fb1 ToddyTheNoobDud: fix: resolve audio stream drops and decoding failures

• 404c49f 1Lucas1apk: fix: defer voice errors to prevent bad disconnects

• 5ac637f 1Lucas1apk: fix: resolve spotify token 400 error caused by clock drift

• 97976b0 1Lucas1apk: fix: update bandcamp stream parsing and regex to prevent fallback

• acaf1e1 ToddyTheNoobDud: fix: loadchapters 500 in cluster mode

• 799e2c0 Ramkrishna: spelling mistake (#208)

• 2138d35 ToddyTheNoobDud: fix: reduce playback memory retention

• ad56e07 ToddyTheNoobDud: fix: shazam failing to resolve songs

• a1afc01 ToddyTheNoobDud: fix: destroy() has already been called on this instance

• 127a974 ToddyTheNoobDud: fix: implement IPC-based worker ID with event socket hello protocol

• 82168e3 UnschooledGamer: fix: enhance error handling for HEAD requests in HTTP source

• e8cc8a5 ToddyTheNoobDud: fix: resolve 11 incompatibilities between player and performanc/voice

• 5c15b29 1Lucas1apk: fix: improve error handling and logging in YouTube cipher service

• fa09a3b 1Lucas1apk: fix: improve error handling and logging in YouTube cipher service

• 32c142d ToddyTheNoobDud: fix: soundcloud urls with query params failing to match

Updated & Improved

• cdb02c6 Lucas Morais Rodrigues: Merge pull request #217 from PerformanC/dev

• 1fdf387 Lucas Morais Rodrigues: Merge pull request #236 from SreerajSK990/fix/core-stability-and-security

• 36c18c4 ToddyTheNoobDud: improve: skip inactive EQ bands and reuse per-frame audio buffers

• 8a5b237 ToddyTheNoobDud: update: make cors configurable

• fb4aee8 Lucas Morais Rodrigues: Merge pull request #231 from filispeen/v3

• be6a555 Lucas Morais Rodrigues: Merge pull request #234 from SreerajSK990/dev

• 0b580ba Lucas Morais Rodrigues: Merge pull request #233 from tropadoratomcleon-source/dev

• a988c62 Lucas Morais Rodrigues: Merge pull request #232 from Akinori107/dev

• 93907a7 ToddyTheNoobDud: improve: refactor shazam to be api only

• 7af723a filispeen: Add Lavalink.lua to supported clients list

• 2b58752 ToddyTheNoobDud: update: add support for searching playlists/artists on spotify

• ff7cc6c Lucas Morais Rodrigues: Merge pull request #229 from Akinori107/dev

• e273f42 ToddyTheNoobDud: update: add player script fallback on error 429

• 351f5c0 ToddyTheNoobDud: improve: bun http/fetch and request shim fixes

• 0a7428d ToddyTheNoobDud: update: make usebunserver default to true

• 2f4134f Lucas Morais Rodrigues: Merge pull request #228 from Akinori107/dev

• 5d32e08 ToddyTheNoobDud: improve: extract bgchallenges from homepage instead of att/get

• 0345c59 Lucas Morais Rodrigues: Merge pull request #227 from Akinori107/dev

• 6299f08 Lucas Morais Rodrigues: Merge pull request #225 from Akinori107/dev

• a92eb23 Lucas Morais Rodrigues: Merge pull request #224 from shhahbaz/fix/prevent-duplicate-stream-events

• 5ca1aa3 ToddyTheNoobDud: update: switch to another visitor_data endpoint

• 4c02946 ToddyTheNoobDud: improve: add fallback to another client during 403s

• ae60a9b Lucas Morais Rodrigues: Merge pull request #222 from shhahbaz/fix/profiler-symlink-escape

• d2eb2bd Lucas Morais Rodrigues: Merge pull request #223 from knownasrazi/fix/audio-stream-bugs

• 22f3535 ToddyTheNoobDud: update: include params in other clients

• 4374f2c 1lucas1apk: Merge branch 'dev' of https://github.com/PerformanC/NodeLink into dev

• 1f9839a 1lucas1apk: improve: enhance smart crossfade transitions and DSP audio effects

• 624fbff Lucas Morais Rodrigues: Merge pull request #221 from SreerajSK990/dev

• 4bbdf8c SreerajSK990: refactor(youtube): use optional chaining for thumbnails

• b4b0bcc 1lucas1apk: Merge branch 'dev' of https://github.com/PerformanC/NodeLink into dev

• c3108d2 ToddyTheNoobDud: update: add support for soundcloud shorten urls

• a1d43d3 ToddyTheNoobDud: improve: visitorData fetching

• 75aa672 1lucas1apk: improve: add mirrorOfficialAlbums option for youtube

• a5e5121 1lucas1apk: update: compiled files in dist

• ff092d7 1lucas1apk: improve: biome write and check

• d57cdc4 ToddyTheNoobDud: improve: general client compatibility

• d62d5f0 toddynnn: Merge pull request #220 from Akinori107/dev

• 76ea67e Lucas Morais Rodrigues: Merge pull request #219 from GDjkhp/dev

• 7f519a6 Lucas Morais Rodrigues: Merge pull request #218 from tropadoratomcleon-source/dev

• 0c90aa5 Emmanuel Lobo: Merge branch 'v3' into dev

• 09db6e6 =: update: readme & dockerfile to reflect new changes

• e34a371 ToddyTheNoobDud: update: respect configured clientId in soundcloud

• 3273cb3 1lucas1apk: Merge branch 'dev' of https://github.com/PerformanC/NodeLink into dev

• 74e3af2 ToddyTheNoobDud: update: add fallback for 403s in newgrounds

• ae4e0d9 ToddyTheNoobDud: improve: support playlist continuations

• b05b301 ToddyTheNoobDud: improve: general maintaince on some sources

• 1bd2a76 ToddyTheNoobDud: update: add direct insta audio playback again

• 3d821fb ToddyTheNoobDud: update: organize sabr types

• c5a0f8b ToddyTheNoobDud: improve: stabilize SABR playback

• f0cb7f0 ToddyTheNoobDud: improve: handle more unicode chars on instagram audio

• e524ed7 ToddyTheNoobDud: improve: memory efficiency & memory leak fixes

• 036ebff ToddyTheNoobDud: update: add support for bun updates in dependecies

• 53c5c9e ToddyTheNoobDud: update: pass the channel_id throught voice updates

• 74483d4 ToddyTheNoobDud: update: bump to typescript 7

• 76d5a66 ToddyTheNoobDud: update: bump clients

• 8b432dd toddynnn: Merge pull request #215 from realkalashnikov/fix/spotify-search

• 24a9afc ToddyTheNoobDud: update: bump version

• 8cbfb71 1Lucas1apk: improve: add aesthetic support guidelines with multiple discord links

• 8db66e0 1Lucas1apk: improve: optimize startup time and drop tsx

• 6b9ce3c ToddyTheNoobDud: update: bump all packages to latest

• e189f47 ToddyTheNoobDud: improve: replace all any usages with correct types & format with biome

• cbb04d5 ToddyTheNoobDud: update: add maintained by on startup

• 7deaa62 Lucas Morais Rodrigues: Merge pull request #212 from kokomo123/patch-1

• 6e64ae5 kokomo123: Remove deprecated version line

• 89aa524 ToddyTheNoobDud: update: remove logger in finishdecode and flush

• b0ede90 1Lucas1apk: update: implement comprehensive manual debug instrumentation

• 3c78be6 1Lucas1apk: improve: modernize architecture and clean up redundancies

• 2419a7d ToddyTheNoobDud: update: include omitBotguardData in player requests

• e5b7a8b 1Lucas1apk: improve: source stability and memory optimizations

• 5e042df 1Lucas1apk: update: improve stuck stream recovery and cache handling

• d36f0aa 1Lucas1apk: update: automatic dependency updates and restart

• 3e9d045 ToddyTheNoobDud: improve: refactor bun support & move to a new file

• 8b1ada1 ToddyTheNoobDud: update: disable monochrome by default

• 17ac8a9 1Lucas1apk: improve: promote core package version logs to info level

• 5e8ba18 1Lucas1apk: improve: implement persistent results cache for dependency checks

• d6551eb 1Lucas1apk: improve: add rate limiting to dependency update checks

• dc0db39 1Lucas1apk: Merge branch 'dev' of https://github.com/PerformanC/NodeLink into dev

• 3098b11 1Lucas1apk: improve: enhanced youtube recovery and itag fallback

• 0beb18a ToddyTheNoobDud: improve: refactor potoken with nativedom & remove jsdom

• 5096f30 Lucas Morais Rodrigues: Update Magmastream entry with version info

• d4f7b52 Lucas Morais Rodrigues: Update Magmastream entry with version info

• 4578973 ToddyTheNoobDud: update: bump version in package.json

• 88b5291 ToddyTheNoobDud: improve: give preference to flac in monochrome; fix: crash on flac seek

• 1162916 ToddyTheNoobDud: update: set mp4box.createFile argument to false

• 6b286b8 ToddyTheNoobDud: make useBunServer default to true

• b94777a ToddyTheNoobDud: improve: stream lifecycle and stream management; fix: bandcamp 403 error

• 2c79e45 ToddyTheNoobDud: update: bump symphonia to 1.1.0

• 936579a 1Lucas1apk: update: bump version to 3.8.1-dev.20260517.1

• 2126718 1Lucas1apk: update: compile source and update build artifacts

• 2dd0378 1Lucas1apk: improve: apply code quality fixes and project-wide linting

• 75a7789 1Lucas1apk: update: implement configuration migration and cache management

• f6f7ced 1Lucas1apk: update: restore robust YouTube visitorData and proxy management logic

• 44bc6f9 1Lucas1apk: update: restore robust YouTube visitorData and proxy management logic

• 372be74 1Lucas1apk: update: sync runtime validation schema with new config structure

• f06155c 1Lucas1apk: update: sync default configuration with new schema

• bfbe8cf 1Lucas1apk: update: flatten config schema and enforce strict unknown typing

• d37908e ToddyTheNoobDud: update: add support for qobuz in monochrome

• af7b092 ToddyTheNoobDud: improve: replace ring buffer with leftover strategy in opus encoder

• 62223ad ToddyTheNoobDud: update: make aead_xchacha20_poly1305_rtpsize the default encryption

• 1eb3fa7 ToddyTheNoobDud: update: add missing type in potoken

• b385604 ToddyTheNoobDud: improve: add v8 heap statics on profiler

What's Changed

• spelling mistake by @ramsquishna in #208
• docs: Remove deprecated version line by @kokomo123 in #212
• fix(spotify): use search.maxResults configuration for search limit by @realkalashnikov in #215
• update: readme & dockerfile to reflect new changes by @tropadoratomcleon-source in #218
• fix: reset fading start postion for gapless by @GDjkhp in #219
• fix: use seekable resource for seeks instead of refetching by @Akinori107 in #220
• fix(youtube): resolve letterboxed hqdefault thumbnails by @SreerajSK990 in #221
• fix: prevent profiler file symlink escapes by @shhahbaz in #222
• fix: resolve audio stream, demuxer, and source bugs by @knownasrazi in #223
• fix: prevent duplicate stream terminal events by @shhahbaz in #224
• fix: register routeplanner sub-routes correctly by @Akinori107 in #225
• fix: forward transition field in 12 AnimatableFilter subclasses by @Akinori107 in #227
• fix: apply skipMarginMs in updateSponsorBlock by @Akinori107 in #228
• fix: recompute trackEnd fade delay for playback speed changes by @Akinori107 in #229
• Add Lavalink.lua to supported clients list by @filispeen in #231
• fix: preserve explicit null endTime through seek pipeline by @Akinori107 in #232
• add: missing file by @tropadoratomcleon-source in #233
• fix(spotify): add GraphQL fallback for recommendations by @SreerajSK990 in #234
• fix: resolve ratelimit, worker eviction, body hang, and path traversal by @SreerajSK990 in #236
• sync: v3 < dev by @1Lucas1apk in #217

New Contributors

• @ramsquishna made their first contribution in #208
• @kokomo123 made their first contribution in #212
• @realkalashnikov made their first contribution in #215
• @tropadoratomcleon-source made their first contribution in #218
• @GDjkhp made their first contribution in #219
• @Akinori107 made their first contribution in #220
• @SreerajSK990 made their first contribution in #221
• @shhahbaz made their first contribution in #222
• @knownasrazi made their first contribution in #223
• @filispeen made their first contribution in #231

Contributors

• @1Lucas1apk (Lucas Morais Rodrigues)
• @ToddyTheNoobDud (toddynnn)
• @SreerajSK990
• @Akinori107 (Akinori)
• @shhahbaz (Shahbaz !!)
• @knownasrazi (Razi)
• @GDjkhp
• @tropadoratomcleon-source
• @filispeen
• @realkalashnikov (rafael)
• @kokomo123
• @ramsquishna (Ramkrishna)
• @UnschooledGamer (Emmanuel Lobo)

Full Changelog:

v3.8.0...v3.9.0