Skip to content

Instantly share code, notes, and snippets.

@BusterNeece
Last active June 16, 2025 16:20
Show Gist options
  • Save BusterNeece/5dbfb4dbc1846055c9ab07a7c685899c to your computer and use it in GitHub Desktop.
Save BusterNeece/5dbfb4dbc1846055c9ab07a7c685899c to your computer and use it in GitHub Desktop.
Liquidsoap 2.1 Video Stream with HLS
# What is This Script?
# This script allows you to broadcast your AzuraCast radio signal to a remote video stream, using a
# static video file that loops in the background and dynamically writing the currently playing track
# on top of that video file.
#
# This script replaces the previous "radio-video-stream" project, allowing you to manage files directly from
# within AzuraCast and not requiring any changes to your Docker configuration at all.
#
# To use this script, you must be running at least AzuraCast 0.19.0 or a later Rolling Release version.
#
# Before Using This Script:
# - Upload a video file to a folder under your station's media library (in the example below, named "videostream")
# - Choose a font to display Now Playing data and upload a TTF version of that font to the same folder
#
# How to Use This Script
# - Copy the section below.
# - Visit your station's "Edit Liquidsoap Configuration" section (under "Broadcasting" in newer versions)
# - Paste the code into the bottom-most configuration section
# - Customize as necessary with your station's media directory and font specifications
# - Click "Save Changes" and then "Restart Broadcasting"
# - Enjoy!
#
# VIDEO STREAM
#
# Edit This: Station Base Directory
station_base_dir = "/var/azuracast/stations/station_name"
# Edit This: YouTube Stream Key
youtube_key = "abcd-1234-abcd-1234"
# Path to the video file that will loop behind the Now Playing text (you have to provide this)
video_file = station_base_dir ^ "/media/videostream/video.mp4"
# Path to a font (TTF) file that will be used to draw the Now Playing text (you have to provide this)
font_file = station_base_dir ^ "/media/videostream/font.ttf"
# A static file auto-generated by AzuraCast in the "config" dir.
nowplaying_file = station_base_dir ^ "/config/nowplaying.txt"
# Align text
font_size = "50"
font_x = "340"
font_y = "990"
font_color = "white"
# Method to overlay now playing text
def add_nowplaying_text(s) =
def mkfilter(graph)
let {video = video_track} = source.tracks(s)
video_track = ffmpeg.filter.video.input(graph, video_track)
video_track = ffmpeg.filter.drawtext(fontfile=font_file,fontsize=font_size,x=font_x,y=font_y,fontcolor=font_color,textfile=nowplaying_file,reload=5,graph,video_track)
video_track = ffmpeg.filter.video.output(graph, video_track)
source({
video = video_track
})
end
ffmpeg.filter.create(mkfilter)
end
videostream = single(video_file)
videostream = add_nowplaying_text(videostream)
videostream = source.mux.video(video=videostream, radio)
# Output to YouTube
enc = %ffmpeg(
format="mpegts",
%video.raw(codec="libx264", pixel_format="yuv420p", b="300k", preset="superfast", r=25, g=50),
%audio(
codec="aac",
samplerate=44100,
channels=2,
b="96k",
profile="aac_low"
)
)
output.youtube.live.hls(key=youtube_key, fallible=true, encoder=enc, videostream)
@radiorecordua
Copy link

Can anyone help me set this up please
Yes, I am

@razl3vi
Copy link

razl3vi commented Feb 20, 2025

Can anyone help me set this up please
Yes, I am

@radiorecordua can u help me pls?

there are 5 section where i can paste this script. is it suppose to be in the lowest one under "# Remote Relays"?
should i join the url and key like this syntax?
stream_key = "rtmp://YOUR RTMP URL/STREAM-KEY"

@radiorecordua
Copy link

Может ли кто-нибудь помочь мне настроить это?
Да, я могу.

@radiorecorduaМожете ли вы мне помочь, пожалуйста?

есть 5 разделов, куда я могу вставить этот скрипт. он должен быть в самом нижнем разделе под "# Remote Relays"? должен ли я объединить URL и ключ следующим образом? stream_key = "rtmp://ВАШ RTMP URL/КЛЮЧ-ПОТОКА"

`#

VIDEO STREAM

Edit This: Station Base Directory

station_base_dir = "/var/azuracast/stations/"

Stream Key

url = " "

Fetch and encode video

video_file = station_base_dir ^ "/media/.mp4"

Write now playing to the video file

font_file = station_base_dir ^ "/media/ttmussels-bolditalic.ttf"

A static file auto-generated by AzuraCast in the "config" dir.

nowplaying_file = station_base_dir ^ "/config/nowplaying.txt"

Align text

font_size = "40"
font_x = "20"
font_y = "900"
font_color = "white"

Method to overlay now playing text

def add_nowplaying_text(s) =
def mkfilter(graph)
let {video = video_track} = source.tracks(s)
video_track = ffmpeg.filter.video.input(graph, video_track)
video_track = ffmpeg.filter.drawtext(fontfile=font_file,fontsize=font_size,x=font_x,y=font_y,fontcolor=font_color,textfile=nowplaying_file,reload=5,graph,video_track)
video_track = ffmpeg.filter.video.output(graph, video_track)

source({
  video = video_track
})

end

ffmpeg.filter.create(mkfilter)
end

videostream = single(video_file)
videostream = add_nowplaying_text(videostream)
videostream = source.mux.video(video=videostream, radio)

Output to YouTube

enc = %ffmpeg(
format="flv",
%video.raw(codec="libx264", pixel_format="yuv420p", b="2500k", preset="superfast", r=25, g=50),
%audio(
codec="aac",
samplerate=44100,
channels=2,
b="96k",
profile="aac_low"
)
)

output.url(fallible=true, url=url, enc, videostream)`

Good afternoon, here is a working configuration for video broadcasting, suitable for any platforms and services, not limited to YouTube, you just need to specify the paths to your working directory and files.

@razl3vi
Copy link

razl3vi commented Feb 21, 2025

Can anyone help me set this up please
Yes, I am

@radiorecordua can u help me pls?

there are 5 section where i can paste this script. is it suppose to be in the lowest one under "# Remote Relays"?
should i join the url and key like this syntax? stream_key = "rtmp://YOUR RTMP URL/STREAM-KEY"

@radiorecordua hi! good afternoon and thank you for the quick response!

I just modified and pasted it and in the save I'm getting error:
"At line 91, char 16: Error 2: Parse error"
if I counted correctly it suppose to be one of those lines:
def add_nowplaying_text(s) =
or
def mkfilter(graph)

just double checking cause I'm not sure, should it goes in the lowest script section? under the line "# Remote Relays" in azuracast liquidsoap overall script?

thank you for your time and help!

@radiorecordua
Copy link

Can anyone help me set this up please
Yes, I am

@radiorecordua can u help me pls?
there are 5 section where i can paste this script. is it suppose to be in the lowest one under "# Remote Relays"?
should i join the url and key like this syntax? stream_key = "rtmp://YOUR RTMP URL/STREAM-KEY"

@radiorecordua hi! good afternoon and thank you for the quick response!

I just modified and pasted it and in the save I'm getting error: "At line 91, char 16: Error 2: Parse error" if I counted correctly it suppose to be one of those lines: def add_nowplaying_text(s) = or def mkfilter(graph)

just double checking cause I'm not sure, should it goes in the lowest script section? under the line "# Remote Relays" in azuracast liquidsoap overall script?

thank you for your time and help!

FireShot Capture 008 - RECORD DANCE RADIO -  live radiorecord com ua

@razl3vi
Copy link

razl3vi commented Feb 21, 2025

Can anyone help me set this up please
Yes, I am

@radiorecordua can u help me pls?
there are 5 section where i can paste this script. is it suppose to be in the lowest one under "# Remote Relays"?
should i join the url and key like this syntax? stream_key = "rtmp://YOUR RTMP URL/STREAM-KEY"

@radiorecordua hi! good afternoon and thank you for the quick response!
I just modified and pasted it and in the save I'm getting error: "At line 91, char 16: Error 2: Parse error" if I counted correctly it suppose to be one of those lines: def add_nowplaying_text(s) = or def mkfilter(graph)
just double checking cause I'm not sure, should it goes in the lowest script section? under the line "# Remote Relays" in azuracast liquidsoap overall script?
thank you for your time and help!

FireShot Capture 008 - RECORD DANCE RADIO - live radiorecord com ua

@radiorecordua thanks again,
it seems we have got different versions, mine is v0.20.4 Stable. which is yours?
do you find it under the main menu under broadcasting -> edit liquidsoap configuration? mine looks different

@radiorecordua
Copy link

radiorecordua commented Apr 27, 2025 via email

@Ferz0id
Copy link

Ferz0id commented May 6, 2025

2025/05/06 14:09:30 [request:3] Nonexistent file or ill-formed URI "/var/azuracast/stations/melodic_drumnbass_radio/video/render.mp4"!

How can I fix this?

@radiorecordua
Copy link

radiorecordua commented May 6, 2025 via email

@alexaungmyooo
Copy link

Rolling Release #d183997 (2025-02-05 17:30) • Docker • PHP 8.4
`Server CPU Specification Summary
Architecture: x86_64 (64-bit)

CPU Model: AMD EPYC Milan Processor @ 2.0 GHz (virtualized under KVM)

CPU Cores: 2 cores (1 socket, 1 core per socket, 2 threads per core / Hyperthreading enabled)

Cache:

L1d: 32 KiB

L1i: 32 KiB

L2: 512 KiB

L3: 32 MiB

Virtualization: KVM full virtualization

Features: SSE, SSE2, AVX, AVX2, AES, Hypervisor support, and others

CPU Usage: (Your monitoring shows max ~70% under load, typical 16%)

Load Average: (1-min: 0.57, 5-min: 0.94, 15-min: 0.74) — indicates light to moderate load`

We're using the Liquidsoap script provided to stream our station to YouTube. As soon as we enabled it, both the radio stream and the video started buffering. This only happens when the YouTube streaming is active—without it, everything runs smoothly.

Our server has sufficient CPU and RAM available, and there's no disk or network bottleneck that we can identify. We suspect the issue may be related to the YouTube streaming configuration, ffmpeg encoder settings, or how the script is handling video looping and audio muxing.

Can you help us identify what might be causing the buffering? Any advice or recommended changes to improve stability would be greatly appreciated.

@alexaungmyooo
Copy link

Может ли кто-нибудь помочь мне настроить это?
Да, я могу.

@radiorecorduaМожете ли вы мне помочь, пожалуйста?
есть 5 разделов, куда я могу вставить этот скрипт. он должен быть в самом нижнем разделе под "# Remote Relays"? должен ли я объединить URL и ключ следующим образом? stream_key = "rtmp://ВАШ RTMP URL/КЛЮЧ-ПОТОКА"

`#

VIDEO STREAM

Edit This: Station Base Directory

station_base_dir = "/var/azuracast/stations/"

Stream Key

url = " "

Fetch and encode video

video_file = station_base_dir ^ "/media/.mp4"

Write now playing to the video file

font_file = station_base_dir ^ "/media/ttmussels-bolditalic.ttf"

A static file auto-generated by AzuraCast in the "config" dir.

nowplaying_file = station_base_dir ^ "/config/nowplaying.txt"

Align text

font_size = "40" font_x = "20" font_y = "900" font_color = "white"

Method to overlay now playing text

def add_nowplaying_text(s) = def mkfilter(graph) let {video = video_track} = source.tracks(s) video_track = ffmpeg.filter.video.input(graph, video_track) video_track = ffmpeg.filter.drawtext(fontfile=font_file,fontsize=font_size,x=font_x,y=font_y,fontcolor=font_color,textfile=nowplaying_file,reload=5,graph,video_track) video_track = ffmpeg.filter.video.output(graph, video_track)

source({
  video = video_track
})

end

ffmpeg.filter.create(mkfilter) end

videostream = single(video_file) videostream = add_nowplaying_text(videostream) videostream = source.mux.video(video=videostream, radio)

Output to YouTube

enc = %ffmpeg( format="flv", %video.raw(codec="libx264", pixel_format="yuv420p", b="2500k", preset="superfast", r=25, g=50), %audio( codec="aac", samplerate=44100, channels=2, b="96k", profile="aac_low" ) )

output.url(fallible=true, url=url, enc, videostream)`

Good afternoon, here is a working configuration for video broadcasting, suitable for any platforms and services, not limited to YouTube, you just need to specify the paths to your working directory and files.

May I know what is the different

format="flv"
output.url(fallible=true, url=url, enc, videostream)

format="mpegts"
output.youtube.live.hls(key=youtube_key, fallible=true, encoder=enc, videostream)

I use your but i got the error

@ruohki
Copy link

ruohki commented Jun 16, 2025

Is there any way to make this work with hardware encoding like h264_vaapi?
just using something like
%video.raw(codec="h264_vaapi", pixel_format="nv12", b="2000k", r=25, g=50) will end up horribly desync or not playabale at all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment