hum
first off, thank you for taking the time to check out the project. posting because i genuinely thought people would find it useful and/or neat. it’s a free TUI player with the ability to play a wide range of local files, rss feeds, and youtube music.
hum repo: github
what the heck does it do and why?
hum not only searches, browses, and plays from ytmusic right from your terminal, it plays your local music and rss feeds as well. utilizing the innertube api key for yt, it requires no login. type, watch autocomplete fill in, hit enter, it streams to a “now-playing” footer with a little spectrum visualizer. search by library, youtube, or both. create playlists with local, yt, or both types of tracks. single binary.
something interesting i learned while putting this thing together:
there’s no public “search music” api, this isn’t the interesting part. however, the youtubei/v1 endpoints that the web app utilizes for devices has actually been pretty heavily reverse engineered to the point it was capable of being implemented as the WEB_REMIX client. this key can actually be found in every youtube music page. i thought that was neat. anyway, the filters for searching (songs, videos, albums, artists) are just ripped base64 protobuf tokens.
.songs => “EgWKAQIIAWoKEAkQBRAKEAMQBA%3D%3D”
.albums => “EgWKAQIYAWoKEAkQChAFEAMQBA%3D%3D”
obviously the innertube json is fucking insanely massive, heavily nested, and pretty undocumented (not publicly by google anyway). google can also alter it whenever they please. instead of taking on the task of modeling the scheme as zig structs, the extractor just walks the std.json.Value recursively and when it hits a musicResponsiveListItemRenderer tries to pull a track from it. if it fails you get ?Track. google can also restructure their surrounding envelope all they want; though having the renderer key allows search to theoretically keep working.
as for the “why?” uh.. because i wanted one idk. i’m also fairly new to zig, come from C and was looking for somewhat of an introductory project. i also spend a lot of time in the terminal and i spend a lot of time with a browser widow pulled up on ytmusic, i figured why not shell out processes and run this thing from a terminal as well, less overhead and it’s neat.
other interesting zig specific bits:
- arena lifetimes continue to bite me. library rows are copied slices out of the index arena (not bytes), i.e. rescanning freed the strings that the results list was still pointing at and the scan progress callback drew them
- that tag reader is structurally a hostile input parser. every tag length is a number, an out of range slice is foobar. to prevent self destruction, all reads are passed through a bounds check, the mp4 atom walker requires forward progress and caps the nesting depth, else it’ll hang the player
- neither
std.crypto.randomorarc4random_bufare portable across all release targets. consequentially, shuffle seeds from ASLR + tick counter (works for the playlist but i feel like this could be better structured)
so it probably has dependencies right?
so, build.zig.zon has an empty dependency set. libmpv is linked C, and yt-dlp and curl are subprocesses.
- for now; as it seems std.http in 0.16 is still moving, libcurl linking was more than required and http is a curl subprocess atm.
- everything takes explicit allocation (arena=per request/gpa=long term)
- the temp writes’ request bodies go to a
mkstempfile (random name, 0600) and passed ascurl --data-binary @fileand are unlinked after use, as opposed to a predictable/tmp/hum_bodypath.
fun fact; the visualizer is a total lie. it mimics a spectrum analyzer but there’s no FFT to be found. mpv runs astats lavfi filter on the audio graph. it reads the overall rms level via the api as a string: af-metadata/vis/lavfi.astats.Overall.RMS_level. dB is converted to linear; each of the 28 bars is modulated off the single envelope value. basically cheap spectrum using scalar.
supported zig versions
zig 0.16
ai / llm usage disclosure
claude code (sonnet 5) was used carefully and sparingly for drafting and refactoring implementation at my direction. it did also help serve as a sounding board while i sorted out the innertube implementation, architecture, design decisions; as i’m trying to better learn zig. every implemented line was read and tested by myself before it shipped. this program was created by a human for humans to serve a very particular purpose.



