Create rich XMLTV Tuner, EPG and RSS feeds from an AzuraCast Web Radio.
If you like what you got, please consider to . Thank you! ❤️
Don’t miss the Discussions! New versions are announced there, and useful hints.
Did you know? You can follow my commits, the discussions or just the announcements using your RSS/Atom feed reader! Just copy-paste the links into your reader as a new subscription and you’ll never miss anything again.
The big picture behind this is to create standards-compliant files to
- easily access your station(s) from almost any media player or server
- get better distribution by providing interested listeners with
- an easy access to your stations and streams
- an electronic program guide (EPG) so they can actively tune in to your shows
- RSS Feeds with show info and direct links to the web player & streams
Therefore I recommend regenerating the files periodically and linking to them on your website, so your listeners can point their media centers/players directly at these links and stay up-to-date with your station(s) automatically.
Unfortunately, there isn’t a "standard" location for this yet. Maybe we should all start using https://domain.tld/xmltv
for that, and
- put an
index.html
(or other) file there that lists the available links in human-readable form, - use this as a base location for the
m3u
andxml
files (i.e., get your station data by pointing tohttps://domain.tld/xmltv/station.m3u
and get the EPG by pointing tohttps://domain.tld/xmltv/domain.tld.xml
). - from version 0.10.0 on, a gzip-compressed version can be made available at
https://domain.tld/xmltv/domain.tld.xml.gz
.
It would make things so much easier for server operators and listeners alike.
You’ll get one M3U file per station (containing that station’s streams), one RSS file per station (containing that station’s scheduled programs, web player and stream links), and one XML EPG file per AzuraCast instance (containing the scheduled programs for all your stations). Since v0.14.0, you also get an additional M3U file per AzuraCast instance (containing ALL station’s streams).
When validated, you can import your M3U "tuner" and the XML EPG into your media center and enjoy a beautiful LiveTV EPG (and playout, of course):
Some applications have no EPG support (yet), but are still nice to use. You can use the M3U tuner file azuracast_xmltv
generates with these:
Hypnotix, the Linux Mint IPTV player (no EPG yet)
Celluloid, a GTK+ frontend for mpv (no EPG)
Station RSS 2.0 Feed, as seen by Nextcloud (v0.12.0 and up)
Note all this may work on Windows machines, but I don’t know. I’m a Linux guy. You’ll run it on your AzuraCast server anyway, right?
- Download
azuracast_xmltv
, put it in a location that’s in your path (on Linux servers, you can use/usr/local/bin
, on desktop systems~/.local/bin
or~/bin
is usually also good). - On a remote server, you can use wget or curl to download it:
wget azuracast_xmltv https://raw.githubusercontent.com/Moonbase59/azuracast_xmltv/master/azuracast_xmltv
curl -o azuracast_xmltv https://raw.githubusercontent.com/Moonbase59/azuracast_xmltv/master/azuracast_xmltv
- Make it executable (
chmod +x azuracast_xmltv
). - Optionally, open in a text editor and modify defaults near the beginning of the file.
Perform a trial run, just executing azuracast_xmltv
. Depending on your operating system, chances are that not all required Python modules are installed, and azuracast_xmltv
will complain about that.
On Debian-like systems, you can easily install the missing modules using pip3
. So let’s assume azuracast_xmltv
complains: ModuleNotFoundError: No module named 'lxml'
. Just go and install it:
pip3 install lxml
Then try again until all required modules are there. You have to do this only once. (On my Ubuntu 22.04 AzuraCast server, only the modules lxml
and tzlocal
were missing.)
Hint: If you don’t even have pip3
, a sudo apt install python3-pip
helps. ;-)
For every new (or modified) station, use the -m
/--m3u
option on the first run, to generate its M3U file. On further runs, this can be omitted and azuracast_xmltv
will only generate fresh EPG XML files.
On servers, just set up a cron job for the software to update the EPG periodically.
Let’s assume you have saved the program as /usr/local/bin/azuracast_xmltv
.
Use crontab -e
to edit your crontab file, and add an entry like this:
# get new EPG data for Jellyfin every 12 hours, 2 minutes past the hour
# avoiding clashes with the AzuraCast demo instance just being reset.
2 */12 * * * /usr/local/bin/azuracast_xmltv -u https://demo.azuracast.com
Add any command line options you want, of course.
If you don’t want the success/failure mails, simply send its output to /dev/null
:
# get new EPG data for Jellyfin every 12 hours, 2 minutes past the hour
# avoiding clashes with the AzuraCast demo instance just being reset.
2 */12 * * * /usr/local/bin/azuracast_xmltv -u https://demo.azuracast.com > /dev/null
Probably after trying out the above on a local machine, you might want to install azuracast_xmltv
on your real AzuraCast server. Let’s assume you run AzuraCast on a remote Ubuntu 22.04 server in a Docker container (standard install) and you wish the output files to be available under https://yourdomain.com/xmltv
as I suggested.
-
Log into your AzuraCast and create an API key for use with
azuracast_xmltv
. You’ll find the function under My Account. Copy the key to a safe place and keep it secret! After creating, you will not be able to view the key again! -
ssh
into your AzuraCast server instance and becomeroot
(sudo su
). -
Install
azuracast_xmltv
as shown above. Put it in/usr/local/bin
. -
Change into the
/var/azuracast
folder and create a subfolderxmltv
. This will later hold the files for your AzuraCast website.cd /var/azuracast mkdir xmltv
-
Modify the
docker-compose.override.yml
file and add an entry for thexmltv
folder in thevolumes
section:nano docker-compose.override.yml
services: web: volumes: - /var/azuracast/xmltv:/var/azuracast/www/web/xmltv
-
Restart your AzuraCast so it can pick up the new settings:
docker-compose down docker-compose up -d
-
Create a crontab entry to run
azuracast_xmltv
periodically, let’s say twice a day, at 2 minutes past the hour:crontab -e
2 */12 * * * /usr/local/bin/azuracast_xmltv -o /var/azuracast/xmltv -u https://yourdomain.com -a 'your_api_key_here' -f -m -t > /dev/null
Save the file.
I left the
-m
option in here (will create M3U files), since my mounts might change, but you can also leave it out and create the M3U manually once. I also set the-f
option to create filler program entries. Use any options you want here.Note: I also use the new
-t
/--tvgurl
option here, since your files can now be found under your server’s/xmltv/
path. This allows more modern software (like KODI) to automatically find the EPG data file (XML) belonging to the M3U. -
Now change into the
xmltv
folder and runazuracast_xmltv
once to check there are no errors, and get the initial set of files. You don’t want to wait for the next automatic update—it might be almost 12 hours away… Use the exact same command you put into the crontab for this, just to be sure everything works./usr/local/bin/azuracast_xmltv -o /var/azuracast/xmltv -u https://yourdomain.com -a 'your_api_key_here' -f -m -t -g
Don’t forget to include the
-m
option, so it’ll create M3U files. -
You should now be able to access the XMLTV data on your public AzuraCast website:
https://yourdomain.com/xmltv/yourstation.m3u https://yourdomain.com/xmltv/yourdomain.com.xml https://yourdomain.com/xmltv/yourdomain.com.xml.gz
Instead of
yourstation
, use the station shortcode you have used when setting up your station. This is the "URL Stub" you might have changed under Edit Station Profile → Profile. You can see this field only in Advanced Mode:Hint: Even if underscores
_
are shown in the example, only use alphanumeric characters and digits, and the hyphen-
to comply with RFC2838. Underscores are not allowed in a domain name. -
Congratulations! You can now publish the above links on your website so your listeners will know where to point their media players and where to get the EPG!
Try it out using any media center or player I mentioned, or just do a quick test with an audio player like Audacious or VLC.
If your client supports the compressed gzip-format (.gz) for the EPG, you should use it. It reduces transmission time and bandwidth.
And don’t forget to log out from your AzuraCast
ssh
session. -
Optional fine-tuning:
a) If your M3U shows some non-public streams and you don’t want that, use the
-p
option to only include streams that are marked public in AzuraCast.b) You might want to edit the programme text that
azuracast_xmltv
generates for the EPG listings and adapt these for your stations. The code is very well documented, justssh
into your server and edit it:sudo nano /usr/local/bin/azuracast_xmltv
. The template texts near the beginning of the file are highly configurable (they use{moustache}
-type variables) so you should be able to adapt to your needs easily.
From the help screen:
usage: azuracast_xmltv [-h] [-v] [-u URL] [-i URL] [-c URL] [-d DAYS] [-f]
[-o FOLDER] [-a APIKEY] [-p] [-m] [--group GROUP] [-r]
[-t] [-g] [--rss]
Create XMLTV Tuner, EPG and RSS Feed files from an AzuraCast Web Radio.
options:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-u URL, --url URL base URL to an AzuraCast instance (default:
https://demo.azuracast.com)
-i URL, --icon URL URL to a channel icon; will use station's default
album art if omitted (default: None)
-c URL, --customplayer URL
URL to a custom web player; modifies {player_url} and
{request_url} variables (default: None)
-d DAYS, --days DAYS number of days in the future [1-30] to include in the
EPG (default: 7)
-f, --fillgaps fill gaps between programmes with a 'General Rotation'
entry (default: False)
-o FOLDER, --output FOLDER
output folder for XMLTV files (default: )
-a APIKEY, --apikey APIKEY
AzuraCast API key; allows creating much better EPG
data, see below (default: None)
-p, --public include only public stations & streams (default:
False)
-m, --m3u create M3U XMLTV Tuner file(s); only needed on first
run or after changes in AzuraCast (default: False)
--group GROUP set M3U 'group-title' to something other than station
name (see below) (default: )
-r, --radio add 'radio="true"' tags to M3U #EXTINF; allows
distinction between radio and TV channels (see below)
(default: True)
-t, --tvgurl add 'tvg-url' tags to M3U file; allows software to
find the corresponding EPG automatically (see below)
(default: False)
-g, --gzip additionally output a gzip-compressed (.gz) version of
the EPG XML file; many clients can use this format,
and it reduces transmission time and bandwidth
(default: True)
--rss create/update RSS 2.0 Feed(s); one feed per station
(default: False)
azuracast_xmltv can create XMLTV M3U Tuner, XML EPG and RSS 2.0 Feed files for
both your own and other AzuraCast stations.
For much better programme data to be generated, create an AzuraCast API key
and use the -a/--apikey option, which allows:
- using otherwise invisible mounts, like an added video stream,
- showing listener request info if a playlist has requests enabled
- adding a presenter image on live shows, and (mis-)using the streamer
comment field as a description
- showing extra info for syndicated content (remote playlists)
--group GROUP modifies the 'group-title' in M3U Tuner files. It normally
contains the station name. Using this, you can group all stations of an
AzuraCast server under a common name, or use something like 'Radio-DE' to
merge with larger, existing lists. A very few clients, like KODI, support
multiple groups. Separate these with a semicolon ';'. Empty values will be
replaced by the station name: ';Radio-DE' --> 'Your Station;Radio-DE',
'Radio;;Radio-DE' --> 'Radio;Your Station;Radio-DE'.
-r/--radio adds a 'radio="true"' tag to the M3U #EXTINF lines, if a stream’s
display name doesn’t contain any of the words 'Video', 'TV', 'Testbild',
'mpeg', 'mpg', 'm2t', 'm2ts', 'ts' (you can customize this list).
This is for software like KODI, which can distinguish between Radio and TV
channels and displays these in separate menus.
-t/--tvgurl adds 'url-tvg' and 'x-tvg-url' tags to the M3U Tuner files. This
helps media center software like KODI to automatically locate the
corresponding EPG data file, but only works if the generated M3U and XML files
are available under the '/xmltv' path of your AzuraCast server.
See installation instructions at
https://github.com/Moonbase59/azuracast_xmltv.
Output files are named after the (sanitized) station shortcode ("URL Stub" in
AzuraCast), and the server base URL.
Edit './azuracast_xmltv' using a text editor to change some defaults near the
top of the file. No worries, everything is well documented.
Please report any issues to
https://github.com/Moonbase59/azuracast_xmltv/issues.
azuracast_xmltv -u https://demo.azuracast.com -m
XMLTV/IPTV "Tuner" files are M3U files, in a special #EXTM3U
format.
azuracast_xmltv
names its output file after your station’s shortcode (called URL Stub in the UI). Ideally, this should only contain alphanumeric characters and the '-' (minus or hyphen).
Sample XMLTV Tuner file azuratest_radio.m3u
#EXTM3U
#EXTINF:-1 tvg-name="/radio.mp3 (128kbps MP3)" tvg-id="azuratest_radio.demo.azuracast.com" group-title="AzuraTest Radio" tvg-logo="https://demo.azuracast.com/api/station/1/art/0",/radio.mp3 (128kbps MP3)
https://demo.azuracast.com/listen/azuratest_radio/radio.mp3
#EXTINF:-1 tvg-name="/mobile.mp3 (64kbps MP3)" tvg-id="azuratest_radio.demo.azuracast.com" group-title="AzuraTest Radio" tvg-logo="https://demo.azuracast.com/api/station/1/art/0",/mobile.mp3 (64kbps MP3)
https://demo.azuracast.com/listen/azuratest_radio/mobile.mp3
#EXTINF:-1 tvg-name="AzuraTest Radio (HLS)" tvg-id="azuratest_radio.demo.azuracast.com" group-title="AzuraTest Radio" tvg-logo="https://demo.azuracast.com/api/station/1/art/0",AzuraTest Radio (HLS)
https://demo.azuracast.com/hls/azuratest_radio/live.m3u8
Beginning with azuracast_xmltv
version 0.7.0, the M3U file entries (mount points) will be sorted by their display name, and the default mount put at the top.
Beginning with azuracast_xmltv
version 0.18.0 and AzuraCast Rolling Release
#c8bcee0 (2023-12-20 1:55), HLS streams set as default will "trump" Icecast/Shoutcast
default streams and be put at the top.
This is mainly intended for players that immediately start playing when opening an M3U file (they should play the default mount first), but also helpful for humans. We just like sorted lists. ;-) Putting HLS first provides easier use for "road warriors", on smartphones and car stereos, due to automatic bandwidth adjustment in areas with varying reception conditions.
More modern playout/media center software like KODI can automatically find the EPG file that corresponds to a M3U, thus reducing manual intervention and setup.
Beginning with version 0.7.0, you can use the -t
/--tvgurl
option to enable this feature. It requires that your generated M3U and XML are reachable from the Internet under your AzuraCast server’s /xmltv/
path. See the Installation instructions on how to achieve this.
XMLTV/IPTV EPG data files are XML files containing channel and program information. They must be compliant with the XMLTV DTD and can be validated using the tv_validate_file
tool, which can be installed on Debian-like systems with sudo apt install xmltv-util
.
This package brings some other nice utilities, just try tv_to_text <yourstation>.xml
.
The XML files azuracast_xmltv
produces are roughly named after RFC2838 - Uniform Resource Identifiers for Television Broadcasts. They look like DNS names, but aren’t, really. We use these names as TV Guide "channel IDs", to hold the M3U and XML data together, so that automated tools like xTeVe, and media servers like Jellyfin or KODI can auto-assign channels and you have less work.
There are some dumber media servers (like Plex, for an example) that don’t handle many M3U/XML files well. This is the reason why we create only one EPG data file per AzuraCast instance (including all its stations).
Sample XMLTV EPG file demo.azuracast.com.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv date="20231018210640 +0200" source-info-url="https://demo.azuracast.com" source-info-name="demo.azuracast.com" generator-info-name="azuracast_xmltv 0.5.0" generator-info-url="https://github.com/Moonbase59/azuracast_xmltv">
<channel id="azuratest_radio.demo.azuracast.com">
<display-name>AzuraTest Radio</display-name>
<icon src="https://demo.azuracast.com/api/station/1/art/0"/>
</channel>
</tv>
Too sad, the AzuraCast demo instance has nothing on schedule right now… Let me show you part of an EPG file from my evaluation station (URLs modified):
Sample XMLTV EPG file niteradio.example.com.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv date="20231018214854 +0200" source-info-url="https://example.com" source-info-name="example.com" generator-info-name="azuracast_xmltv 0.5.0" generator-info-url="https://github.com/Moonbase59/azuracast_xmltv">
<channel id="niteradio.example.com">
<display-name>Nite Radio</display-name>
<icon src="https://example.com/api/station/1/art/0"/>
</channel>
<programme start="20231018060000 +0200" stop="20231018120000 +0200" channel="niteradio.example.com">
<title lang="en">Pop (requests enabled)</title>
<sub-title lang="en">Your favorite station, YOUR music!</sub-title>
<desc lang="en">Playlist: Pop
The request lines are open! Make this program YOURS by adding a request.
Go to https://example.com/public/niteradio, click on ›Request Song‹ and select your favorite.
</desc>
<credits/>
<category lang="en">Music</category>
</programme>
<programme start="20231018120000 +0200" stop="20231018160000 +0200" channel="niteradio.example.com">
<title lang="en">Live: Moonbase</title>
<desc lang="en">Streamer: Moonbase
Live Show, hosted by Moonbase.
In his unmistakable way, Moonbase presents highlights of music history: Kraut and progressive rock, classic, glam and hard rock. Some metal, too. Some of his shows are centered around the finest electronic music in existence, most notably the Berlin School.
You CAN be excited. Or just have fun!
</desc>
<credits>
<presenter>Moonbase<image type="person">https://example.com/api/station/1/streamer/1%7C1678618644/art</image></presenter>
</credits>
<category lang="en">Music</category>
</programme>
...
<programme start="20231021180000 +0200" stop="20231022000000 +0200" channel="niteradio.example.com">
<title lang="en">Heart Dance from London, UK</title>
<desc lang="en">Playlist: Heart Dance from London, UK
(Syndicated content.)
</desc>
<credits/>
<category lang="en">Music</category>
</programme>
<programme start="20231022000000 +0200" stop="20231022060000 +0200" channel="niteradio.example.com">
<title lang="en">Nuit électronique (requests enabled)</title>
<sub-title lang="en">Your favorite station, YOUR music!</sub-title>
<desc lang="en">Playlist: Nuit électronique
The request lines are open! Make this program YOURS by adding a request.
Go to https://example.com/public/niteradio, click on ›Request Song‹ and select your favorite.
</desc>
<credits/>
<category lang="en">Music</category>
</programme>
</tv>
Now this looks like some program, right?
From version 0.12.0, azuracast_xmltv
can optionally generate RSS 2.0 Feeds, too. Using the --rss
option, these can be created/updated together with the EPG in one go. We produce one file per station, which can easily be cached for great performance.
The RSS feeds build on the already existing, flexible customization logic and can even use HTML code (although some readers strip some HTML elements). You get a chronological feed with all your shows, image, description, web player and stream links. My generator uses modern technologies, <media:…>
elements and all.
Station RSS Feed as seen by Nextcloud.
Scheduled programmes are presented in a chronological list, click on a list entry for more information, or click the globe icon to directly jump to the station’s web player to make a request.
Single programme as seen by Nextcloud
The description is highly configurable, as with the EPG, but you can even use HTML here.
A click on the image opens the web player.
Station RSS Feed as seen by the Firefox "Livemarks" extension
The RSS feed looks good even in the most basic feed reader. A click on the title opens the web player, but here you also have direct links to all the station’s streams. Listeners enjoy the information, and your station is always only one click away.
Station RSS Feed as seen by Liferea (a famous Linux feed reader)
You can even use the web player within some feed readers
The RSS 2.0 Feeds we generate are standards-compliant and usually validate just fine. Some validators have problems with feed items lying in the future, that can safely be ignored.
We use the most modern technologies and the most compatible set of features, so chances are good that a feature is already there when feed readers finally catch up. Currently, not every feed reader supports all features.
It makes no sense for an EPG to have a zillion entries called /radio.mp3 (128kbps MP3)
. Seriously. A station might not even have a logo, so how would you distinguish all these in a large EPG?
The above will happen when you leave the mount point Display Name empty, it’s just AzuraCast’s default.
My suggestion: Change the Display Name of your station’s mount points to something meaningful that everyone can easily find and distinguish in the EPG. azuracast_xmltv
will automatically pick up the change when you run it with the -m
/--m3u
option next time.
As an example, I used
- Nite Radio (128kbps AAC)
- Nite Radio (128kbps MP3)
- Nite Radio Testbild
- Nite Radio Video-Stream
The HLS stream (if you have one), will automatically be named <Your Station Name> (HLS)
.
Some media center software (like KODI) can distinguish between "Radio" and "TV" and puts streams under "Radio" and "TV" menus, respectively. The distinction is made by a flag radio="true"
on the M3U #EXTINF
lines.
From version 0.11.0, azuracast_xmltv
fully supports this feature if the -r
/--radio
option is used (default).
azuracast_xmltv
will look for a list of keywords in your stream name, and flag it a video stream if any of the following keywords are found in the stream display name: Video
, TV
, Testbild
, mpeg
, mpg
, m2t
, m2ts
, ts
. The comparison is case-insensitive, also expanding some language-specific characters, like the German "ß" to "ss".
You can edit the default keyword list near the beginning of the file. It is called videostream_keywords
.
In KODI this will later look like this:
To be supplied.
Read the built-in help in the meantime: azuracast_xmltv --help
.
You don’t have many scheduled shows but a 24/7 station and want to show that something is playing in the EPG?
azuracast_xmltv
has the concept of fillers. Just use the -f
/--fillgaps
option and it will create nice programme entries for the times in between shows, and your listeners will know something is playing on the station.
The filler logic takes the playlist names that constitute your general rotation (enabled, type default, not on schedule), so name your playlists wisely. Let’s say you had a general rotation built of the 'Classic Rock', 'Folk Rock' and 'Hard Rock' playlist. azuracast_xmltv
then generates a {playlists}
variable for you that looks like Classic Rock, Folk Rock & Hard Rock
and can be used in the configuration.
The default filler can be configured in the options near the start of the script file:
# "Gap Filler" text to be shown when a programme is actually a gap filler.
# After parsing, the gap_filler_title will be used as playlist name and the result
# RE-PARSED by the requests_enabled parser, if ANY of the involved playlists has
# requests enabled. Descriptions from here and the requests enabled parsing will
# be APPENDED to each other (the request text coming beneath).
# this will be used as a programme's title
gap_filler_title = "24/7 Rock"
# this will be used as a programme's subtitle
gap_filler_subtitle = "{playlists}"
# this will be the programme's description
# Your text should make sense even if {playlists} is empty!
# Multiple successive blanks will be automatically replaced by a single blank.
gap_filler_description = """Your favorite sound, 24 hours a day, 7 days a week.
The best {playlists} in {year} — just here, on {station_name}."""
With our example, the generated EPG playlist entry would then look like this:
<programme start="20231020170000 +0200" stop="20231020180000 +0200" channel="niteradio.example.com">
<title lang="en">24/7 Rock</title>
<sub-title lang="en">Classic Rock, Folk Rock & Hard Rock</sub-title>
<desc lang="en">Your favorite sound, 24 hours a day, 7 days a week.
The best Classic Rock, Folk Rock & Hard Rock in 2023 — just here, on Nite Radio.
Program Copyright © 2023 Nite Radio — Non-public test & evaluation server only
Visit us on https://example.com</desc>
<credits/>
<category lang="en">Music</category>
</programme>
(The copyright part coming from another element, namely the append_to_description
text.)
Before going public, you should always check if your setup validates as correct XMLTV data.
On Debian-like systems, install the xmltv-util
package:
sudo apt install xmltv-util
then validate your EPG file using:
tv_validate_file niteradio.example.com.xml
Validated ok.
Here is another nice trick: Output the EPG as text in your terminal!
tv_to_text niteradio.example.com.xml
10-18 (Wednesday)
06:00--12:00 Pop (requests enabled) // Your favorite station, YOUR music! Nite Radio
12:00--16:00 Live: Moonbase Nite Radio
10-21 (Saturday)
18:00--00:00 Heart Dance from London, UK Nite Radio
10-22 (Sunday)
00:00--06:00 Nuit électronique (requests enabled) // Your favorite station, YOUR music! Nite Radio
Generated from example.com by azuracast_xmltv 0.5.0.
Or even with long descriptions:
tv_to_text --with-desc radio.niteradio.net.xml
10-18 (Wednesday)
06:00--12:00 Pop (requests enabled) // Your favorite station, YOUR music! Nite Radio Playlist: Pop The request lines are open! Make this program YOURS by adding a request. Go to https://example.com/public/niteradio, click on ›Request Song‹ and select your favorite.
12:00--16:00 Live: Moonbase Nite Radio Streamer: Moonbase Live Show, hosted by Moonbase. In his unmistakable way, Moonbase presents highlights of music history: Kraut and progressive rock, classic, glam and hard rock. Some metal, too. Some of his shows are centered around the finest electronic music in existence, most notably the Berlin School. You CAN be excited. Or just have fun!
10-21 (Saturday)
18:00--00:00 Heart Dance from London, UK Nite Radio Playlist: Heart Dance from London, UK (Syndicated content.)
10-22 (Sunday)
00:00--06:00 Nuit électronique (requests enabled) // Your favorite station, YOUR music! Nite Radio Playlist: Nuit électronique The request lines are open! Make this program YOURS by adding a request. Go to https://example.com/public/niteradio, click on ›Request Song‹ and select your favorite.
Generated from example.com by azuracast_xmltv 0.5.0.
azuracast_xmltv
will work with any AzuraCast instance that uses scheduled programming, even stations that might not be your own. Please don’t overuse this—polling for a fresh EPG every 12, 24, or 48 hours is usually enough!
When using your own station, I recommend setting up an API key in your AzuraCast and use the -a
/--apikey
option, which will enable enhanced functionality and provide a much richer EPG.
If you use an API key, it will allow:
- using otherwise invisible mounts, like an added video stream
- customizable Live Show title/sub-title/description (streamer/DJ info)*
- customizable Live Show DJ info (mis-using Streamer Comment field)
- Live Show DJ image (if provided in AzuraCast); this is added as an
image of type "person" in the programme's
<presenter>
info. Not all clients may support this (they'll just ignore it). - customizable listener requests info (for playlists that have requests enabled)
- customizable syndication info (for playlists that are remote streams)
- gap filler
{playlists}
info
* This also works without an API key.
This is just a Python script, so you can open it using a text editor. (Windows users: No editors that produce a BOM, please! Use something like Notepad++.)
Near the beginning of the file, you’ll find many user-customizable options, most notably the program title/sub-title and description text to go with…
- live shows (streamer/DJ),
- syndicated content (remote playlists),
- playlists that have listener requests enabled,
- gap filler programmes, and
- RSS Feeds (HTML allowed here).
You can also set defaults for most options here. These will be shown when --help
is invoked.
azuracast_xmltv
can be used and imported as a Python module. Just rename (or symlink) it to have a .py
file extension.
All usual module functions should work, like import
, help and documentation with tools like pdoc
.
Using this type of marking a variable part of text is commonly used. While executing, azuracast_xmltv
will replace these with the actual content, for example replace {year}
with 2023
(if the programme starts in 2023). azuracast_xmltv
will also automatically remove any leftover extra whitespace after replacing the variables.
"Extra whitespace" is, for instance, multiple blanks in succession or extra linefeeds at the end of the text. This can happen when a variable to be replaced is actually empty.
An example:
You might have specified The best {playlists} in {year}.
in the gap_filler_description
, which would normally expand to The best Classic Rock, Folk Rock & Hard Rock in 2023.
But you haven’t used an API key, which is needed to use {playlists}
, so we would get The best in 2023.
The double space looks awful, right?
azuracast_xmltv
will automatically detect this and correct to The best in 2023.
Much better!
{station_name}
{station_description}
{station_website}
— the station website URL (this is not the AzuraCast URL){player_url}
** — station’s web player URL{year}
— start year of the programme{category}
— global category, usually "Music"
{playlist}
— playlist name{request_url}
** — station’s web player URL
{playlist}
— playlist name{remote_url}
— remote URL used in the playlist
{presenter}
— streamer/DJ name{image_url}
* — streamer’s image URL{comments}
* — AzuraCast’s Streamer Comments field content.
Note: Comments should be used with care: This field was originally meant for internal remarks only, you could leak data!
{playlists}
* — comma-separated list of playlist names that make up the general rotation (enabled, type default, not on schedule).
So if your general rotation was made up of the playlistsClassic Rock
,Folk Rock
andHard Rock
, it would showClassic Rock, Folk Rock & Hard Rock
.
{title}
— programme title{subtitle}
— programme sub-title{airdate}
— date of programme start "YYYY-MM-DD"{airtime}
— programme start & end time "HH:MM–HH:MM"{airtime_length}
— programme length "HH:MM"{desc}
— original programme description, generated from above elements. Newlines in{desc}
will automatically be converted to<br/>
.
* = This can only be used with an API key, i.e., on your own station.
** = URL to AzuraCast’s web player, or a custom player specified using the -c
/--customplayer
option. Use the latter to point listeners to a customized player on your station’s website instead of the default one.
This can happen in the initial server verification phase and is actually a warning. azuracast_xmltv
will try to continue if it can find a live AzuraCast server.
In the case shown, your request was redirected from a http://
to a https://
URL.
Since HTTP status 301 means "moved permanently", you should re-invoke the command,
this time using the https://
URL. The URL you give on the commandline is used
to construct the URLs in the various M3U, XML and RSS files, and you wouldn’t want
to publicize "wrong" URLs. Even if they work, it looks unprofessional and generates
unnecessary traffic.
There are situations where you want to keep the un-redirected URLs, though.
Let’s assume your server is in maintenenace and you have a temporary redirect
to a backup server for the time being (307 Temporary Redirect). In this case,
you want to keep the "old" URLs and just let azuracast_xmltv
continue.
In almost all cases, this means the API key given didn’t work. azuracast_xmltv
will continue as if no API key had been given.
The user who generated the API key in AzuraCast must have appropriate rights to access the station’s …
- mounts,
- playlists, and
- streamers/DJs.
Or maybe there was a typo or a character left out while copying the API key.
I get HTTPError – 500 Server Error: Internal Server Error for url: https://…/api/station/STATION_ID/mounts
This means the station with ID STATION_ID
has no mounts. Maybe they aren’t set up yet, or the station is HLS-only and doesn’t use Icecast or Shoutcast.
azuracast_xmltv
will continue normally.
Timezones should be handled correctly: Linux servers, AzuraCast, azuracast_xmltv
, the XMLTV EPG file standard, and the clients know about timezones.
You can set your station’s timezone in AzuraCast, and azuracast_xmltv
will simply use the timezone of the machine it runs on. Since azuracast_xmltv
normally runs on your AzuraCast server (which should be set up correctly, ask your system administrator), all should be well.
If you experience any problems (like EPG hours being offset), it is usually the client software’s fault (the EPG reading application). The files azuracast_xmltv
generates contain the correct timezone UTC offsets as specified in the protocol.
Both AzuraCast and azuracast_xmltv
handle this correctly, if the server has been set up correctly.
Here is an example of a programme that runs on 2023-10-29 00:00–06:00 in Germany. Now that night at 03:00 clocks in Germany will be reset to 02:00 since daylight savings time ends. The generated EPG code looks like this:
<programme start="20231029000000 +0200" stop="20231029060000 +0100" channel="niteradio.example.com">
<title lang="en">Nuit électronique</title>
<desc lang="en">Playliste: Nuit électronique</desc>
<credits/>
<category lang="en">Music</category>
</programme>
As you can see, the UTC time offset at the start of the programme is +0200
, and +0100
at its end. A standards-compliant EPG client should be able to handle this correctly. The programme starts at 00:00 daylight savings time and ends at 06:00 normal time, making for an actual duration of 7 hours.
Absolutely. Many clients like KODI and xTeVe support reading this format. Since files are much smaller, it decreases transmission time and bandwidth drastically.
Some clients don’t yet support the modern, compressed version of the EPG. Offer both and let the client decide which to use.
This is also the reason why the url-tvg
and x-tvg-url
entries in the M3U file (if you use the -t
/--tvgurl
option) point to the .xml
version of the file, not to the gzipped version.
I can’t give support for the many applications that use this format, but here’s a short list of apps I have tested or know they work fine with azuracast_xmltv
:
- Jellyfin* – The Free Software Media System
- KODI* – Entertainment Center
- Plex – (non-free)
- Emby – (non-free)
- TVHeadend* – TV Streaming Server and Recorder
- Hypnotix* – The Linux Mint IPTV player (no EPG yet)
- Celluloid* – A simple GTK+ frontend for mpv (no EPG); default video player in Linux Mint
- VLC* – The VLC media player (no EPG)
- xTeVe* (GitHub) (Documentation) – M3U Proxy, recommended
- Liferea*, Thunderbird*, Nextcloud* – are/have good RSS feed readers (just a random selection, because I use all of these)
Many others are out there in the wild. Consult their documentation to find how to set up "XMLTV" or "IPTV". In KODI, some are under "PVR …" (Personal Video Recorder).
Here are some links for looking up related items:
- The XMLTV DTD*
- XMLTV.org
- Kodi: IPTV einrichten – (heise online; German)
- What is Live TV, PVR and Radio? – (KODI FAQ)
- PVR IPTV Simple Client* – IPTV client for KODI
- Kodinerds – KODI-related German Forum
- Kodinerds IPTV - Freie und legale Streams für Kodi – Free and legal streams for IPTV; German, but has international channels.
- ErsatzTV* – Your Personal IPTV Server
- The RSS 2.0 Specification* – RSS Advisory Board
* Free and Open Source Software I personally use and recommend.