Skip to content

Instantly share code, notes, and snippets.

@yshalsager
Last active October 24, 2025 19:40
Show Gist options
  • Select an option

  • Save yshalsager/d92d6b8a90a39c1d5a9a6001651f814a to your computer and use it in GitHub Desktop.

Select an option

Save yshalsager/d92d6b8a90a39c1d5a9a6001651f814a to your computer and use it in GitHub Desktop.
Quran Radio Stream Helper: a script wraps ffmpeg to pull a single Quran radio feed, add a live-updating title overlay, and restream it to multiple Telegram live-stream keys.

Quran Radio Stream Helper

This script wraps ffmpeg to pull a single Quran radio feed, add a live-updating title overlay, and restream it to multiple Telegram live-stream keys.

Dependencies

  • ffmpeg and ffprobe
  • writable runtime directory for the title file ($TITLE_FILE or default)
  • network access to the source radio feed and Telegram RTMPS endpoints

Environment Variables

Variable Purpose Default
STREAM_URL Source audio stream URL https://backup.qurango.net/radio/tarateel
TEE_TARGETS Pipe-separated tee muxer targets hard-coded list of RTMPS endpoints
TITLE_FILE Path to text file read by drawtext %t/radio-title.txt (systemd runtime dir)
DEFAULT_TITLE Fallback overlay text Quran Radio
FONT Font file for drawtext /usr/share/fonts/truetype/noto/NotoSansArabic-Bold.ttf

Override any of them in the launching environment; most importantly supply fresh Telegram stream keys through TEE_TARGETS.

Running Manually

STREAM_URL=https://backup.qurango.net/radio/tarateel \
TEE_TARGETS='[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1305…|[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1409…' \
DEFAULT_TITLE='Quran Radio' \
FONT=/usr/share/fonts/truetype/noto/NotoSansArabic-Bold.ttf \
TITLE_FILE=/run/user/$(id -u)/radio-title.txt \
/usr/bin/env bash scripts/radio_stream.sh

The script will:

  1. Fetch the current StreamTitle via ffprobe and write it to $TITLE_FILE.
  2. Spawn ffmpeg with a still black background and drawtext overlay that reloads the file on metadata updates.
  3. Restream audio/video to every target specified in TEE_TARGETS using the tee muxer.

Watch stderr (or the systemd journal) for lines like Metadata update for StreamTitle: to confirm overlay refreshes.

Sample systemd User Unit

Create ~/.config/systemd/user/radio.service (adjust paths and keys):

[Unit]
Description=quran radio
After=network.target

[Service]
Type=exec
Restart=always
RestartSec=5
RuntimeMaxSec=1h
Environment=STREAM_URL=https://backup.qurango.net/radio/tarateel
Environment=TITLE_FILE=%t/radio-title.txt
Environment=DEFAULT_TITLE=Quran Radio
Environment=FONT=/usr/share/fonts/truetype/noto/NotoSansArabic-Bold.ttf
Environment=TEE_TARGETS=[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1305…|[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1409…|[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1420…|[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc1-1.rtmp.t.me/s/1478…
ExecStart=/usr/bin/env bash /home/USERNAME/radio_stream.sh
MemoryMax=256M
CPUQuota=100%
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
ProtectControlGroups=true
ProtectKernelTunables=true
RestrictAddressFamilies=AF_INET AF_INET6
RestrictNamespaces=true
RestrictRealtime=true
SystemCallArchitectures=native

[Install]
WantedBy=default.target

Replace every with the full Telegram stream key and swap USERNAME for your login. Keep the keys fresh whenever you start a new live session.

If you want the service to survive logouts, enable linger with loginctl enable-linger USERNAME.

systemd Usage (User Mode)

systemctl --user daemon-reload
systemctl --user enable --now radio.service
# Monitor logs
journalctl --user-unit radio.service -f

If only one output goes live, ensure each Telegram channel is in “Go Live” state and that all keys inside TEE_TARGETS are current. The onfail=ignore flag keeps other outputs running when any single destination rejects the publish.

#!/usr/bin/env bash
set -euo pipefail
stream_url=${STREAM_URL:-https://backup.qurango.net/radio/tarateel}
tee_targets=${TEE_TARGETS:-'[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/1305...|[f=flv:onfail=ignore:flvflags=no_duration_filesize]rtmps://dc4-1.rtmp.t.me/s/2204....'}
title_file=${TITLE_FILE:-/run/user/$UID/radio-title.txt}
default_title=${DEFAULT_TITLE:-Quran Radio}
font_path=${FONT:-/usr/share/fonts/truetype/noto/NotoSansArabic-Bold.ttf}
mkdir -p "$(dirname "$title_file")"
write_title() {
local text=$1
[[ -z $text ]] && text=$default_title
local tmp="${title_file}.tmp"
printf '%s\n' "$text" > "$tmp"
mv "$tmp" "$title_file"
}
initial_title=$(ffprobe -v error -icy 1 -show_entries format_tags=StreamTitle -of default=nw=1:nk=1 "$stream_url" 2>/dev/null || true)
write_title "$initial_title"
trap 'rm -f "${title_file}.tmp"' EXIT
ffmpeg -hide_banner -nostats -loglevel repeat+verbose \
-thread_queue_size 1024 \
-reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2 -icy 1 \
-i "$stream_url" \
-f lavfi -thread_queue_size 16 -i color=size=480x270:rate=2:color=black \
-filter_complex "[1:v]drawtext=fontfile='$font_path':fontsize=18:fontcolor=white:textfile=$title_file:reload=1:box=1:boxcolor=0x000000@0.75:boxborderw=36:x=(w-text_w)/2:y=(h-text_h)/2[v]" \
-map "[v]" -map 0:a \
-c:v libx264 -preset ultrafast -tune stillimage -profile:v baseline -level 3.0 -crf 35 -maxrate 150k -bufsize 500k \
-g 4 -keyint_min 2 -bf 0 -refs 1 -me_method dia -subq 0 -trellis 0 \
-sc_threshold 0 -force_key_frames 'expr:gte(t,n_forced*2)' -pix_fmt yuv420p -r 2 -threads 2 \
-c:a aac -b:a 48k -ar 44100 -ac 2 \
-flags +global_header -f tee "$tee_targets" \
2> >(stdbuf -oL bash -c '
set -eo pipefail
title_file="$1"
default_title="$2"
write_title_sub() {
local text="$1"
[[ -z $text ]] && text="$default_title"
local tmp="${title_file}.tmp"
printf "%s\n" "$text" > "$tmp"
mv "$tmp" "$title_file"
}
while IFS= read -r line; do
printf "%s\n" "$line" >&2
if [[ $line == *"Metadata update for StreamTitle:"* ]]; then
extracted=${line#*Metadata update for StreamTitle:}
extracted=${extracted## }
extracted=${extracted%%$'\r'}
write_title_sub "$extracted"
fi
done
' bash "$title_file" "$default_title")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment