Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- # -*- coding: utf-8 -*-
- '''
- 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-eit2.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
- '''
- from __future__ import print_function
- from datetime import datetime, timedelta
- import argparse
- import logging
- import re
- import sys
- import time
- from MythTV.services_api import send as api
- from MythTV.services_api import utilities as util
- from xml.etree.ElementTree import Element, SubElement, tostring
- DAY_IN_SECONDS = 24 * 60 * 60
- TIME_NOW = time.mktime(datetime.now().timetuple())
- WHITE = '\033[0m'
- YELLOW = '\033[93m'
- def flags_to_strings(flgs):
- '''
- Convert the decimal flags to a printable string. From:
- libs/libmyth/programtypes.h. The </> print for values that
- haven't been defined here yet (and maybe should be.)
- '''
- strlst = list()
- if flgs & (0x00fff):
- strlst.append('<')
- if flgs & (1 << 12):
- strlst.append('Rerun')
- if flgs & (1 << 13):
- strlst.append('Dup')
- if flgs & (1 << 14):
- strlst.append('React')
- if flgs & (0xf8000):
- strlst.append('>')
- return ', '.join(strlst)
- def process_command_line():
- parser = argparse.ArgumentParser(description='Fetch EPG data for specified channels from a mythtv database and export this data to an XMLTV formatted XML file',
- epilog='Default values are in ()s')
- parser.add_argument('--debug', action='store_true',
- help='turn on debug messages (%(default)s)')
- parser.add_argument('--digest', type=str, metavar='<user:pass>',
- help='digest username:password')
- parser.add_argument('--forcehd', action='store_true', default=False,
- help='forces all output programmes to be flagged as HD (%(default)s)')
- parser.add_argument('--host', type=str, required=False,
- default='localhost',
- metavar='<hostname>',
- help='backend hostname (%(default)s)')
- parser.add_argument('--output', type=str, default='./output.xml', metavar='<file>',
- help='output XML file name (%(default)s)')
- parser.add_argument('--port', type=int, default=6544, metavar='<port>',
- help='port number of the Services API (%(default)s)')
- parser.add_argument('--shift', type=int, default=0, metavar='<time shift>',
- help='time in minutes to move programme data (%(default)s)')
- parser.add_argument('--version', action='version', version='%(prog)s 0.10')
- parser.add_argument('channels', metavar='chanidN,xmlidN', nargs="+", type=str,
- help='list of chanid & xmlid pairs e.g. chanid1,xmlid1 chanid2,xmlid2 chanidN,xmlidN')
- return parser.parse_args()
- def d2s(dateobj, tshift):
- """
- Reads datetime string from services api and returns a string in XLMTV format with timezone & time shift offsets.
- """
- date = datetime.strptime(dateobj, "%Y-%m-%dT%H:%M:%SZ")
- tshift = -tshift
- #tshift = tshift + time.altzone//60 ---> no need to adjust for local timezone?
- return date.strftime("%Y%m%d%H%M%S"+ ' ' + "{:+03d}".format(tshift//60) + "{:02d}".format(tshift%60))
- def writexmltv(elem, file):
- f = open(file,'w')
- print ("Writing XMLTV EPG information to file %s\n" % file)
- f.write('<?xml version="1.0" ?>\n')
- f.write('<!DOCTYPE tv SYSTEM "xmltv.dtd">\n')
- #write tv XML element including all program subelements
- f.write(tostring(elem, encoding="unicode"))
- f.close()
- def main():
- '''
- Get the channel program info from the backend and process it
- '''
- args = process_command_line()
- opts = dict()
- logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO)
- logging.getLogger('requests.packages.urllib3').setLevel(logging.WARNING)
- logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)
- channels={}
- for chan in args.channels:
- try:
- c,x=chan.split(",")
- except:
- print ("Error: Not able to parse channel %s. Aborting...\n" % chan)
- usage()
- sys.exit(2)
- try:
- testint=int(c)
- except:
- print ("Error: Channel number is not an integer. Aborting...\n")
- usage()
- sys.exit(2)
- if len(x) == 0:
- print ("Error: XMLTVID is not specified for channel %s. Aborting...\n" % (c))
- usage()
- sys.exit(2)
- print (c,x)
- channels[int(c)]=x
- try:
- opts['user'], opts['pass'] = args.digest.split(':')
- except (AttributeError, ValueError):
- pass
- #################################################################
- # Request the program listing from the backend and check the #
- # response ... #
- #################################################################
- endpoint = 'Guide/GetProgramList'
- backend = api.Send(host=args.host)
- util.get_utc_offset(backend=backend, opts=opts) # not needed?
- #create xml object "tv"
- tv = Element('tv')
- for chan in channels:
- rest = 'chanid=' + str(chan) + '&Details=true'
- try:
- resp_dict = backend.send(endpoint=endpoint, rest=rest, opts=opts)
- except RuntimeError as error:
- sys.exit('\nFatal error: "{}"'.format(error))
- count = int(resp_dict['ProgramList']['TotalAvailable'])
- programs = resp_dict['ProgramList']['Programs']
- if args.debug:
- print('Debug: Count of found programmes= {}'.format(count))
- if count < 1:
- print('\nNo matching 'visible' channels found.\n')
- sys.exit(0)
- #Read schedule for each channel and create XML elements
- for program in programs:
- tvprogram = SubElement(tv, 'programme', channel=channels[chan],
- start=d2s(program['StartTime'],args.shift),
- stop=d2s(program['EndTime'],args.shift))
- tvtitle = SubElement(tvprogram, 'title')
- tvtitle.text = program['Title']
- tvsubtitle = SubElement(tvprogram, 'sub-title')
- tvsubtitle.text = program['SubTitle']
- tvdesc = SubElement(tvprogram, 'desc')
- tvdesc.text = program['Description']
- tvcategory = SubElement(tvprogram, 'category')
- tvcategory.text = program['Category']
- if program['Repeat']=='true':
- tvprevshown = SubElement(tvprogram, 'previously-shown')
- tvprevshown.text = ' /'
- tvairdate = SubElement(tvprogram, 'date')
- tvairdate.text = program['Airdate']
- tvepnum = SubElement(tvprogram, 'episode-num')
- tvepnum.text = program['Episode']
- if args.forcehd:
- tvvideo = SubElement(tvprogram, 'video')
- tvquality = SubElement(tvvideo, 'quality')
- tvquality.text = 'HDTV'
- writexmltv(tv, args.output)
- if __name__ == '__main__':
- main()
- # vim: set expandtab tabstop=4 shiftwidth=4 smartindent colorcolumn=80:
Add Comment
Please, Sign In to add comment