index.html (11116B)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <link rel="stylesheet" href="/style.css" type="text/css"> 5 <meta charset="utf-8"> 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 <link rel="stylesheet" type="text/css" href="/style.css"> 9 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🏕️</text></svg>"> 10 <title></title> 11 </head> 12 <body> 13 <div id="page-wrapper"> 14 <div id="header" role="banner"> 15 <header class="banner"> 16 <div id="banner-text"> 17 <span class="banner-title"><a href="/">beauhilton</a></span> 18 </div> 19 </header> 20 <nav> 21 <a href="/about">about</a> 22 <a href="/now">now</a> 23 <a href="/thanks">thanks</a> 24 <a class="nav-active" href="/posts">posts</a> 25 <a href="https://notes.beauhilton.com">notes</a> 26 <a href="https://talks.beauhilton.com">talks</a> 27 <a href="https://git.beauhilton.com">git</a> 28 <a href="/contact">contact</a> 29 <a href="/atom.xml">rss</a> 30 </nav> 31 </div> 32 <main> 33 <h1> 34 Command-line interfaces for self-hosted music 35 </h1> 36 <p> 37 <time id="post-date">2023-09-28</time> 38 </p> 39 <p id="post-excerpt"> 40 Self-hosting a music server is great. 41 Listening to the tunes via the command line is the way. 42 </p> 43 <h2> 44 Subsonic-compatible server backbone 45 </h2> 46 <p> 47 I have <a href="https://www.navidrome.org/">Navidrome</a> installed 48 (via Docker on NixOS). It’s very nice. 49 </p> 50 <p> 51 With a reverse proxy, <a href="https://tailscale.com/">tailscale</a>, 52 and LetsEncrypt set up, I can access it via any Subsonic-compatible 53 music player at <a href="https://music.beauslab.casa">https://music.beauslab.casa</a> (this 54 URL is available only on my tailnet, so it will 404 for everyone 55 else). 56 </p> 57 <h2> 58 Desktop GUI interfaces 59 </h2> 60 <p> 61 <a href="https://sublimemusic.app/">Sublime-music</a> is pretty good. 62 I also often find myself using the Navidrome web UI. 63 </p> 64 <p> 65 (On mobile, <a href="https://symfonium.app/">Symfonium</a> (paid) or 66 <a href="https://substreamerapp.com/">SubStreamer</a> on Android and <a href="http://michaelsapps.dk/playsubapp/">play:Sub</a> (paid) or <a href="https://substreamerapp.com/">SubStreamer</a> on iOS are my go-tos, 67 though there are many <a href="http://www.subsonic.org/pages/apps.jsp">others</a>) 68 </p> 69 <h2> 70 CLI interfaces: contenders (STMP, jellycli, sksonic) 71 </h2> 72 <p> 73 If I’m in programming mode, I prefer command-line interfaces, 74 particularly if they let me use keyboard muscle-memory (i.e. vi 75 bindings). 76 </p> 77 <p> 78 As such, I tried a few CLI front-ends to access and play my 79 Navidrome-served tunes. 80 </p> 81 <p> 82 I’m sure there are others. 83 </p> 84 <p> 85 <a href="https://github.com/wildeyedskies/stmp/tree/main">STMP</a> is 86 clean and works well, but doesn’t have vi bindings yet. 87 </p> 88 <p> 89 <a href="https://github.com/tryffel/jellycli/tree/master">jellycli</a> is 90 the most polished, and uses vi bindings, but even so the in-app nav is 91 finicky and doesn’t quite fit my brain (though that might be mostly due 92 to conflicts with other terminal keybindings I have set up). 93 </p> 94 <p> 95 <a href="https://gitlab.com/yvelon/sksonic">sksonic</a> is a 96 suckless-style implementation in C, e.g. edit config.h and recompile. It 97 works, but isn’t polished enough for daily usage (though I don’t expect 98 it to be - the author states it’s a personal project, and I think 99 they’re doing a great job, so will keep an eye on it). Partial vi-key 100 support, could easily be added given the suckless style. 101 </p> 102 <h2> 103 CLI interfaces: the one I picked (ncmpcpp with mopidy backend) 104 </h2> 105 <p> 106 After these, I found myself wishing that I could use <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> and hook it up to 107 my Subsonic back end. 108 </p> 109 <p> 110 And then I realized: hey, this is a Linux TUI, and ncmpcpp is just a 111 front-end for <a href="https://www.musicpd.org/">mpd</a>, of course you 112 can switch out mpd for something that’s Subsonic-aware. 113 </p> 114 <p> 115 ncmpcpp is beautiful, polished, fast, with great vi-key support, and 116 I’ve been using it for years for local music playback. 117 </p> 118 <p> 119 <a href="https://mopidy.com/">mopidy</a> is a fairly drop-in mpd 120 replacement that is pluggable, with a number of awesome <a href="https://mopidy.com/ext/">extensions</a>. 121 </p> 122 <p> 123 I should have looked here first. C’est la vie. 124 </p> 125 <p> 126 I perused a few blog posts to get a sense of what to do: 127 </p> 128 <ul> 129 <li> 130 <a href="https://fsylum.net/blog/setting-up-ncmpcpp-mopidy-spotify-arch-linux/">fsylum’s 131 post</a> 132 </li> 133 <li> 134 <a href="https://blog.deepjyoti30.dev/using-spotify-with-ncmpcpp-mopidy-linux">Deepjyoti 135 Barman’s post</a> 136 </li> 137 <li> 138 <a href="https://www.digitalneanderthal.com/post/ncmpcpp/">Digital 139 Neanderthals’ post</a> (what a great online moniker, well done - his 140 physical setup is also a delight, sheer cyberdeck practicality) 141 </li> 142 </ul> 143 <p> 144 It’s pretty easy. 145 </p> 146 <p> 147 The rad thing is that you can get a unified frontend for all your 148 sources, e.g. Subsonic, Spotify, local files, YouTube, SoundCloud, etc., 149 just install a plugin and add a config section and you’re off to the 150 races, never having to leave the terminal. 151 </p> 152 <blockquote> 153 <p> 154 Source selection (could have many more items here). 155 </p> 156 </blockquote> 157 <p> 158 <img src="/images/ncmpcpp-mopidy-selector.png" alt="Source selection"> 159 </p> 160 <blockquote> 161 <p> 162 Artist selection. 163 </p> 164 </blockquote> 165 <p> 166 <img src="/images/ncmpcpp-mopidy-full.png" alt="Preview"> 167 </p> 168 <blockquote> 169 <p> 170 Track view. 171 </p> 172 </blockquote> 173 <p> 174 <img src="/images/ncmpcpp-mopidy-tracks.png" alt="Track view"> 175 </p> 176 <h2> 177 Set up 178 </h2> 179 <h3> 180 Install the things 181 </h3> 182 <p> 183 My main laptop still runs Arch (btw). If I ever switch to NixOS on 184 this machine, or add this setup to the NixOS server, I’ll probably make 185 a new post with the Nix way to do this. I bet it’s hardly different, 186 other than the <code>.nix</code> files. 187 </p> 188 <p> 189 e.g. <code>paru -S ncmpcpp mopidy mopidy-subidy mopidy-mpd</code> 190 </p> 191 <p> 192 Also uninstall and stop mpd, if you’re using it. 193 </p> 194 <h3> 195 Config files 196 </h3> 197 <p> 198 (most of the what’s in the files below is unnecessary for this post, 199 but I’ve never been mad that someone posted their whole config) 200 </p> 201 <p> 202 (also note that the mopidy config file doesn’t allow # comments, I 203 just used them for ease of reading with syntax highlighting, will have 204 to delete prior to actually using) 205 </p> 206 <p> 207 <code>~/.config/ncmpcpp/config</code> 208 </p> 209 <pre tabindex="0"><code class="language-sh">ncmpcpp_directory <span class="hl opt">=</span> ~<span class="hl opt">/</span>.config<span class="hl opt">/</span>ncmpcpp 210 lyrics_directory <span class="hl opt">=</span> ~<span class="hl opt">/</span>.config<span class="hl opt">/</span>lyrics 211 212 progressbar_look <span class="hl opt">= -></span> 213 display_volume_level <span class="hl opt">=</span> no 214 215 autocenter_mode <span class="hl opt">=</span> <span class="hl kwc">yes</span> 216 message_delay_time <span class="hl opt">=</span> <span class="hl num">1</span> 217 218 playlist_display_mode <span class="hl opt">=</span> columns 219 playlist_editor_display_mode <span class="hl opt">=</span> columns 220 browser_display_mode <span class="hl opt">=</span> columns 221 222 media_library_primary_tag <span class="hl opt">=</span> album_artist 223 media_library_albums_split_by_date <span class="hl opt">=</span> no 224 225 ignore_leading_the <span class="hl opt">=</span> <span class="hl kwc">yes</span> 226 ignore_diacritics <span class="hl opt">=</span> <span class="hl kwc">yes</span> 227 external_editor <span class="hl opt">=</span> vim 228 use_console_editor <span class="hl opt">=</span> <span class="hl kwc">yes</span> 229 </code></pre> 230 <p> 231 <code>~/.config/mopidy/mopidy.conf</code> 232 </p> 233 <pre tabindex="0"><code class="language-sh"><span class="hl opt">[</span>core<span class="hl opt">]</span> 234 cache_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CACHE_DIR</span><span class="hl opt">/</span>mopidy 235 config_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CONFIG_DIR</span><span class="hl opt">/</span>mopidy 236 data_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_DATA_DIR</span><span class="hl opt">/</span>mopidy 237 max_tracklist_length <span class="hl opt">=</span> <span class="hl num">10000</span> 238 restore_state <span class="hl opt">=</span> true 239 240 <span class="hl opt">[</span><span class="hl kwc">file</span><span class="hl opt">]</span> <span class="hl slc"># might switch out for mopidy-local at some point, adds search support via sqlite metadata archive</span> 241 enabled <span class="hl opt">=</span> true 242 media_dirs <span class="hl opt">=</span> 243 ~<span class="hl opt">/</span>media<span class="hl opt">/</span>tunes 244 excluded_file_extensions <span class="hl opt">=</span> 245 .directory 246 .html 247 .jpeg 248 .jpg 249 .log 250 .nfo 251 .pdf 252 .png 253 .txt 254 .<span class="hl kwc">zip</span> 255 show_dotfiles <span class="hl opt">=</span> false 256 follow_symlinks <span class="hl opt">=</span> false 257 metadata_timeout <span class="hl opt">=</span> <span class="hl num">1000</span> 258 259 <span class="hl opt">[</span>m3u<span class="hl opt">]</span> 260 playlists_dir <span class="hl opt">=</span> <span class="hl kwd">$XDG_CONFIG_DIR</span><span class="hl opt">/</span>mopidy<span class="hl opt">/</span>playlists 261 262 <span class="hl opt">[</span>mpd<span class="hl opt">]</span> 263 enabled <span class="hl opt">=</span> true 264 hostname <span class="hl opt">=</span> <span class="hl num">127.0.0.1</span> 265 port <span class="hl opt">=</span> <span class="hl num">6600</span> <span class="hl slc"># defaults ftw - no change to ncmpcpp config needed if defaults are kept</span> 266 max_connections <span class="hl opt">=</span> <span class="hl num">20</span> 267 connection_timeout <span class="hl opt">=</span> <span class="hl num">60</span> 268 269 <span class="hl opt">[</span>subidy<span class="hl opt">]</span> 270 enabled <span class="hl opt">=</span> true 271 url <span class="hl opt">=</span> https<span class="hl opt">://</span>music.beauslab.casa 272 username <span class="hl opt">=</span> admin 273 password <span class="hl opt">=</span> admin <span class="hl slc"># behind a tailnet anyway, come at me bro</span> 274 api_version <span class="hl opt">=</span> <span class="hl num">1.16</span> 275 </code></pre> 276 <h2> 277 Future goals 278 </h2> 279 <ul> 280 <li> 281 snapcast for whole-house audio (<a href="https://www.reddit.com/r/selfhosted/comments/icjmiq/a_music_server_with_a_tli_client/">Reddit 282 post</a> with some good tips) 283 </li> 284 </ul> 285 </main> 286 <div id="footnotes"></div> 287 <footer></footer> 288 </div> 289 </body> 290 </html>