A while ago, I’ve found an article on Hackaday, describing how to stream arbitrary YouTube videos to Sonos systems. Before you ask: No, that’s not possible normally, at least not without a premium subscription.
In the original article called How I hacked SONOS and YouTube the same day (lol?????), the author described an approach to grab audio streams from YouTube and to convert them into ADTS streams on-the-fly to convince a Sonos device to play some YouTube music. For this, an MP3 radio station is created that Sonos uses as a source, all without the requirement to first download a video to disk and then streaming it to Sonos afterwards. Some parts seem rather complicated, such as manually parsing MP4 containers to extract AAC audio content. Also, there’s another issue: The author still didn’t release the full source code and also did not (yet?) release the announced mobile app to perform these tasks.
(╯°□°)╯︵ ┻━┻
So today, I’ll present this hefty one-liner that does all of that stuff:
(tmux has-session -t yt 2>/dev/null || tmux new-session -d -s yt) && tmux neww -d \
"ffmpeg -i \
'$(python3 -m youtube_dl --user-agent BestUserAgent -f bestaudio,mp4 -g 'https://www.youtube.com/watch?v=zwu8hgUyr2E' | head -1)' \
-user_agent BestUserAgent -q:a 0 -map a -f mp3 pipe:1 | \
cvlc -vvv - --sout '#standard{access=http,mux=mp3,dst=0.0.0.0:3636}' --file-caching 10000 --network-caching 10000"
OK! This does the following things:
- Execute all of the following stuff in a new
tmux
session, for convenience and to be able to run it on a server. - Use
youtube-dl
to grab a streaming link from YouTube for the specific video. Normally, you’d usestreamlink
for this, but some YouTube videos are protected and do not allow simple access to the respective streaming links. Luckily,youtube-dl
uses its own JS interpreter to even extract streams for protected content. The-f
parameter foryoutube-dl
controls the desired content format. Most of the time, it would be fine to just grab an audio only stream, however some music live streams only offer video streams, for whatever reason. For this purpose,bestaudio,mp4
is specified as a format to just try getting both a music and a video stream. If an audio only stream is available, that one is used instead of the one containing additional video content. Here’s a list of available formats that can be specified with the-f
parameter:
youtube-dl --list-formats 'https://www.youtube.com/watch?v=zwu8hgUyr2E'
[youtube] zwu8hgUyr2E: Downloading webpage
[info] Available formats for zwu8hgUyr2E:
format code extension resolution note
251 webm audio only tiny 125k , webm_dash container, opus @125k (48000Hz), 3.20MiB
140 m4a audio only tiny 127k , m4a_dash container, mp4a.40.2@127k (44100Hz), 3.25MiB
278 webm 192x144 144p 28k , webm_dash container, vp9@ 28k, 15fps, video only, 751.12KiB
394 mp4 192x144 144p 34k , mp4_dash container, av01.0.00M.08.0.110.06.01.06.0@ 34k, 15fps, video only, 912.75KiB
160 mp4 192x144 144p 109k , mp4_dash container, avc1.4d400c@ 109k, 15fps, video only, 2.79MiB
395 mp4 320x240 240p 42k , mp4_dash container, av01.0.00M.08.0.110.06.01.06.0@ 42k, 15fps, video only, 1.10MiB
242 webm 320x240 240p 65k , webm_dash container, vp9@ 65k, 15fps, video only, 1.69MiB
133 mp4 320x240 240p 245k , mp4_dash container, avc1.4d400d@ 245k, 15fps, video only, 6.27MiB
18 mp4 320x240 240p 325k , avc1.42001E, 15fps, mp4a.40.2 (44100Hz), 8.33MiB (best)
- Use
ffmpeg
to get the stream contents, piping them to the next application on-the-fly and without downloading the full stream first. - Use
cvlc
, the CLI version ofvlc
, to create an audio stream Sonos is able to interpret. This accomplished with an HTTP stream, similar to an MP3 web radio, as described in the VLC documentation. It also uses some caching to prevent buffering during playback.
The only thing that’s left is to point Sonos to the audio stream, for example with:
from soco import SoCo
zone = SoCo("10.1.3.37")
zone.play_uri("x-rincon-mp3radio://10.1.2.3:3636")
The x-rincon-mp3radio
handler allows specifying the MP3 stream opened by cvlc
and we’re done!
This should work with every YouTube video and can be integrated into a chat bot or some other handy thing.
ヾ(⌐■_■)ノ♪ |̲̅̅●̲̅̅|̲̅̅=̲̅̅|̲̅̅●̲̅̅|