One-liner to do this using yt-dlp (better alternative to youtube-dl) and jq JSON processor:
yt-dlp --dump-json videoIDorURL | jq --raw-output ".chapters[].title"
To get starting timestamps:
| jq --raw-output ".chapters[].start_time" | awk '{printf("%d:%02d:%02d\n",($1/60/60%24),($1/60%60),($1%60))}'
With paste and process substitution you can combine both. This is a function you could add to your .bashrc/.zshrc:
function get_chapters_times() { paste <(yt-dlp --dump-json $1 | jq --raw-output ".chapters[].start_time" | awk '{printf("%d:%02d:%02d\n",($1/60/60%24),($1/60%60),($1%60))}') <(yt-dlp --dump-json $1 | jq --raw-output ".chapters[].title") }
Will return:
$ get_chapters_times https://youtu.be/DxL2HoqLbyA 0:00:00 Intro 0:02:15 History 0:04:16 Ideal Engine 0:09:48 Entropy 0:11:03 Energy Spread 0:14:49 Air Conditioning 0:17:26 Life on Earth 0:19:35 The Past Hypothesis 0:21:43 Hawking Radiation 0:23:31 Heat Death of the Universe 0:24:52 Conclusion
Use yt-dlp --split-chapters to download each chapter.