#!/usr/bin/python3 # -*- coding: utf-8 -*- # Fixed for python3 on 2020-04-10 # JSW 2021-09-05 Pretty print the XML output to prevent huge line lengths (and make it readable). # JSW 2021-09-06 Added UTC timezone offset to times to fix a mythfilldatabase warning when reading files created by cross-eit.py. """ This program fetches schedule information from a mythtv database and exports this data to an XMLTV [1] formatted XML file. check usage(): for further description """ import os import datetime import time import sys import getopt from MythTV import Guide from lxml.etree import Element, SubElement, tostring def usage(): print("""This script fetches EPG data for specified channels from a mythtv database and exports this data to an XMLTV [1] formatted XML file. The purpose of this is to extract EPG from channels with good data, and use this data to populate other channels where no data is available. Script usage: cross-eit.py OPTIONS chanid1,xmlid1 chanid2,xmlid2 chanidN,xmlidN Options: -o, --output=file Write output to XML file. If this argument is not specified output is written to ./output.xml -h, --help Show help text (this text) To check the channel numbers for the channels you want to extract EPG from, run the following command: mysql -u mythtv -p mythconverg -e \"SELECT chanid,callsign from channel WHERE callsign='channel name'\" If you want to import the EPG data from the xml file using mythfilldatabase, you must add the appropriate xmltvid for each channel you want to import EPG to in mythweb [2] as well as uncheck the useonairguide for these channels. Example: (assuming sourceid of 1 for mythtv) ./cross-eit.py 1004,tv2.guide 1108,history.guide 1022,natgeo.guide -o /tmp/export.xml mythfilldatabase -v xmltv --file 1 /tmp/export.xml [1] http://wiki.xmltv.org/index.php/XMLTVFormat [2] http://localhost/mythweb/settings/tv/channels """) def read_arguments(argv): """ Reads arguments argv, checks for valid options and parses channel information. Returns output file and channels """ output="output.xml" try: opts, args = getopt.getopt(argv, "ho:", ["help", "output="]) except getopt.GetoptError: usage() sys.exit(2) for opt, arg in opts: if opt in ("-h", "--help"): usage() sys.exit(2) elif opt in ("-o", "--output"): output = arg if len(args) == 0: print("Error: No channels specified. Aborting...\n" % (args)) usage() sys.exit(2) channels={} for arg in args: try: c,x=arg.split(",") except: print("Error: Not able to parse channel %s. Aborting...\n" % (arg)) usage() sys.exit(2) try: testint=int(c) except: print("Error: Channel number is not an integer - check you syntax. Aborting...\n") usage() sys.exit(2) if len(x) == 0: print("Error: please XMLTVID is not specified for channel %s. Aborting...\n" % (c)) usage() sys.exit(2) channels[int(c)]=x return channels, output def d2s(dateobj): """ Reads dateobject and returns a string in XLMTV format with timezone offset of "+0000" as all the times from the MythTV database are in UTC. """ return dateobj.strftime("%Y%m%d%H%M%S +0000") class MyGuide( Guide ): @classmethod def fromChanID(cls, chanid, db=None): return cls._fromQuery("WHERE chanid=%s", (chanid,), db) def schedule(channels): """ Retrives EPG for channels 'channels'. Returns XML ELement 'tv' """ #create xml object "tv" tv = Element('tv') #Read schedule for each channel and create XML elements for chan in channels: print("Processing channel number: %s, XMLTV id: %s" % (chan, channels[chan])) count = 0 for prog in MyGuide.fromChanID(chan): count += 1 program = SubElement(tv, 'programme', channel=channels[chan], start=d2s(prog.starttime), stop=d2s(prog.endtime)) title = SubElement(program, 'title') title.text = prog.title subtitle = SubElement(program, 'sub-title') subtitle.text = prog.subtitle desc = SubElement(program, 'desc') desc.text = prog.description category = SubElement(program, 'category') category.text = prog.category if int(prog.previouslyshown) == 1: prev = SubElement(program, 'previously-shown') print("Number of processed programs: %d\n" % count) return tv def writexmltv(elem, file): f = open(file,'w') print("Writing XMLTV EPG information to file %s\n" % file) f.write('\n') f.write('\n') #write tv XML element including all program subelements f.write(tostring(elem, pretty_print=True, encoding="unicode")) f.close() def main(args): """ Main script """ version = "v2.1" print("cross-eit %s\n" % version) channels, outputfile = read_arguments(args) xmltags=schedule(channels) writexmltv(xmltags, outputfile) if __name__ == "__main__": main(sys.argv[1:])