Brandon Sanderson has been releasing a few chapters a week of his upcoming novel, Wind and Truth, on his publisher’s website leading up to its December 6th release. This includes the audiobook chapters, but they’re posted to Soundcloud and there’s no good way to listen at 1.6x speed. This post is a note sheet on how to download audio from Soundcloud and prepare it for my audiobook reader.

Get a package manager

First step is to get uv. I’ve been very excited to watch this fast tool replace many iffy Python packaging tools!

$ curl -LsSf https://astral.sh/uv/install.sh | sh

See also the full installation documentation.

Install the downloader tool

yt-dlp is a feature-rich command-line audio/video downloader with support for thousands of sites.

Second step is to install yt-dlp using uv tool install. uv installs the tool and its CLI in an isolated virtual environment but makes it available globally on your system.

$ uv tool install yt-dlp
Resolved 1 package in 106ms
Installed 1 package in 28ms
 + yt-dlp==2024.11.18
Installed 1 executable: yt-dlp

Look how fast it installs with a warm cache!

Download the audio

The chapters for Wind and Truth are indexed here. For example, you can navigate to interludes 3 and 4, scroll to the bottom, then open the Soundcloud embed in a new browser tab and copy the URL.

Third step is to invoke yt-dlp from the console with the URL as the only argument (in quotes!). The best thing about this tool is that it has a plugin-based architecture, so it can deal with basically anything you give it.

$ yt-dlp "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1931715512%3Fsecret_token%3Ds-WvtAtAMqqkc&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true"
[SoundcloudEmbed] Extracting URL: https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1931715512%3Fsecret_toke...ser=true&visual=true
[soundcloud] Extracting URL: https://api.soundcloud.com/tracks/1931715512?secret_token=s-WvtAtAMqqkc
[soundcloud] 1931715512: Downloading info JSON
[soundcloud] 1931715512: Downloading hls_mp3 format info JSON
[soundcloud] 1931715512: Downloading http_mp3 format info JSON
[soundcloud] 1931715512: Downloading hls_opus format info JSON
[info] 1931715512: Downloading 1 format(s): hls_opus_64
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 136
[download] Destination: Interludes - WIND AND TRUTH by Brandon Sanderson, narrated by Kate Reading and Michael Kramer [1931715512].opus
[download] 100% of   10.10MiB in 00:00:04 at 2.14MiB/s

Convert the audio’s format

The only issue is that it gives output in the Opus file format, which isn’t so easy to use. The fourth step is to convert this to m4b for easy use with an audiobook reader. After installing ffmpeg (e.g., with brew install ffmpeg), run

$ ffmpeg \
    -i "Interludes - WIND AND TRUTH by Brandon Sanderson, narrated by Kate Reading and Michael Kramer [1931715512].opus" \
    -c:a aac -b:a 128k -vn -f ipod interludes-3-and-4.m4b
ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
  built with Apple clang version 16.0.0 (clang-1600.0.26.4)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.100 / 61. 19.100
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Input #0, ogg, from 'Interludes - WIND AND TRUTH by Brandon Sanderson, narrated by Kate Reading and Michael Kramer [1931715512].opus':
  Duration: 00:22:12.36, start: 0.000000, bitrate: 63 kb/s
  Stream #0:0: Audio: opus, 48000 Hz, stereo, fltp
      Metadata:
        encoder         : Lavc58.91.100 libopus
Stream mapping:
  Stream #0:0 -> #0:0 (opus (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, ipod, to 'interludes-3-and-4.m4b':
  Metadata:
    encoder         : Lavf61.7.100
  Stream #0:0: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s
      Metadata:
        encoder         : Lavc61.19.100 aac
[out#0/ipod @ 0x6000016e4000] video:0KiB audio:20840KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 1.175908%
size=   21086KiB time=00:22:12.34 bitrate= 129.6kbits/s speed=43.8x
[aac @ 0x151004f50] Qavg: 668.452

Easy listening

I’m using BookPlayer, an open source project to listen to books. I usually sync them by using AirDrop to send the m4b files to my phone, then using its import menu.


Happy listening!

P.S., I wrote a script that automates crawling the Wind and Truth index, downloading, and converting these files.