Skip to content

Instantly share code, notes, and snippets.

@Moonbase59
Created October 14, 2023 21:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Moonbase59/b76ab3b565dba65a9695b1f72d78d931 to your computer and use it in GitHub Desktop.
Save Moonbase59/b76ab3b565dba65a9695b1f72d78d931 to your computer and use it in GitHub Desktop.
Proof of concept: XMLTV.xml for AzuraCast. Quick-n-dirty.
#!/usr/bin/env python3
# encoding: utf-8
# azuracast_xmltv.py
# 2023-10-14 - Moonbase - initial version - QUICK-N-DIRTY!
#
# Parses station 1’s schedule into XMLTV.xml format,
# writes to stdout (or a file).
#
# Depending on your Python installation, you might need to install
# lxml and tzlocal:
# pip3 install lxml
# pip3 install tzlocal
import requests
import json
import lxml.etree as et
import tzlocal
import datetime as dt
# file to create
xmltv_file = '/dev/stdout'
# The AzuraCast API will apparently return entries for one day max.
api_url = "https://example.com/api/station/1/schedule?now=now&rows=100"
response = requests.get(api_url, headers={"accept": "application/json"})
if response.status_code == 200:
if response.headers["Content-Type"] == "application/json":
r = response.json()
#for item in r:
# print(item['start'], item['end'], item["name"])
# set up the root
root = et.Element("tv",
attrib={"source-info-name": "azuracast_xmltv", "generator-info-name": "azuracast_xmltv"})
# set up the channel
channel = et.SubElement(root, "channel", attrib={"id": "niteradio.de"})
et.SubElement(channel, "display-name").text = "Nite Radio"
et.SubElement(channel, "icon",
attrib={"src": "https://example.com/static/uploads/album_art.1678623041.png"})
# set up programs
local_timezone = tzlocal.get_localzone()
for r_pgm in r:
attrib_lang = {"lang": "en"}
# 2023-10-15T22:00:00+02:00
start = dt.datetime.strptime(r_pgm["start"], "%Y-%m-%dT%H:%M:%S%z")
stop = dt.datetime.strptime(r_pgm["end"], "%Y-%m-%dT%H:%M:%S%z")
programme_attrib = dict(
start=start.astimezone(local_timezone).strftime("%Y%m%d%H%M%S %z"),
stop=stop.astimezone(local_timezone).strftime("%Y%m%d%H%M%S %z"),
channel="niteradio.de")
programme = et.SubElement(root, "programme", attrib=programme_attrib)
#et.SubElement(programme, "title", attrib=attrib_lang).text = r_pgm["title"]
#et.SubElement(programme, "sub-title", attrib=attrib_lang).text = r_pgm["description"]
et.SubElement(programme, "desc", attrib=attrib_lang).text = "Wir spielen die bessere Musik."
et.SubElement(programme, "category", attrib=attrib_lang).text = "Music"
if r_pgm["type"] == "streamer":
# Show "Live: Presenter Name" in the title, as in the video stream
et.SubElement(programme, "title", attrib=attrib_lang).text = 'Live: ' + r_pgm["title"]
credits = et.SubElement(programme, "credits")
et.SubElement(credits, "presenter").text = r_pgm["name"]
else:
# AutoDJ playlist, just use the title
et.SubElement(programme, "title", attrib=attrib_lang).text = r_pgm["title"]
with et.xmlfile(xmltv_file, encoding="UTF-8") as xf:
xf.write_declaration()
xf.write_doctype('<!DOCTYPE tv SYSTEM "xmltv.dtd">')
xf.write(root, pretty_print=True)
quit()
@Moonbase59
Copy link
Author

Moonbase59 commented Oct 23, 2023

This was a simple proof of concept and has since been superceded by https://github.com/Moonbase59/azuracast_xmltv, which has much more features and is more robust.

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