#! /usr/bin/env python # # Author: Ben Holroyd # License: GPL 3.0+ # # Usage: # Put an entry in ~/.config/openbox/menu.xml: # #called without args just checks that listings are up to date for that day #-t prints in plain text to stdout #-p is for use in pipe menus from HTMLParser import HTMLParser from urllib import FancyURLopener from threading import Thread import datetime,os from optparse import OptionParser #dict of channels with channel codes, need to get from radio times website channellistdict = {'BBC1':'92','BBC2':'105','ITV':'26','Channel4':'132','Five':'134'} #need a separate list, as dict gets out of order channellist=['BBC1','BBC2','ITV','Channel4','Five'] #where temporary files are kept tmpfile = "/tmp" #dont touch tmpfile=os.path.join(tmpfile,"%%s-%s" % datetime.date.today()) address="http://www.radiotimes.com/ListingsServlet?event=4&jspGridLocation=%%2Fjsp%%2Ftv_listings_grid.jsp&jspListLocation=%%2Fjsp%%2Ftv_listings_single.jsp&jspError=%%2Fjsp%%2Ferror.jsp&listingsFormat=L&channels=%s" class pageparser(HTMLParser): def __init__(self, data, channel): """parse downloaded pages, and save by channel in tmp""" HTMLParser.__init__(self) self.bltime = False self.bltitle = False self.time = '' #hack-- htmlparser doesnt like original form, even though its in comments data = data.replace("","") self.file = open(tmpfile % channel, 'w') self.feed(data) def handle_starttag(self, tag, attrs): if tag == 'p' and attrs: if attrs[0][1] == 'startTime': self.bltime = True if attrs[0][1] == 'progTitle': self.bltitle = True def handle_data(self,data): if self.bltime == True: self.time = data self.bltime = False if self.bltitle == True: self.file.write('%s%%%s\n' % (data, self.time)) #print "Title: ",data, 'time: ', self.time self.bltitle = False class downloader(Thread): """threaded downloader for webpages""" def __init__ (self, url, channelcode, channel): Thread.__init__(self) self.channel = channel self.channelcode = channelcode self.url = url def run(self): try: data = FancyURLopener().open(self.url % self.channelcode).read() except IOError: pass pageparser(data, self.channel) class printer(): """print parsed files""" def __init__(self, channel): self.now = datetime.datetime.now() self.channel = channel #check we have listings for the correct day if not os.path.exists(tmpfile % self.channel): downloader(address,channellistdict[self.channel],self.channel).start() file = open(tmpfile % self.channel, 'r').read() data = [line.split('%') for line in file.split('\n') if len(line) > 0] #find most recent program, then trim 'data' to fit. for index, [programme, time] in enumerate(data): if self.comparetime(time): if index == 0: index = 1 #just in case a programme starts just before midnight self.data = data[index-1:] break def comparetime (self,cmp_time): """returns true if time supplied is bigger than current time""" hour, minute = self.now.hour, self.now.minute #converts 'hh:mm a/pm' to int, pam strips pm and am from string cmp_hour,cmp_minute = map(int, cmp_time.rstrip('pam').split(':')) #convert to 24hr time, & sort 12am, 12pm if cmp_time.endswith('pm') and cmp_hour != 12: cmp_hour += 12 if cmp_time.endswith('am') and cmp_hour == 12: cmp_hour -= 12 return (cmp_hour, cmp_minute) > (hour, minute) def showxmlmenu(self): print " " % (self.channel,self.channel) print " " % (self.data[0][0],self.data[0][1]) print " " % (self.data[1][0],self.data[1][1]) print " " % (self.channel) for programme, time in self.data[2:]: print " " % (programme,time) print " " print " " def showplaintext(self): for programme, time in self.data: print programme, ' Starts: ', time parser = OptionParser( version=" %prog V0.1 Ben Holroyd", description = "%prog - print tv listings, if called without options will check\nthat the listings are upto date and redownload if needed", usage = "%prog [-tp] [--text] [--pipe] [--help]") parser.add_option("-t", "--text", action="store_true", dest="text", default=False, help="print tvlistings in plain text") parser.add_option("-p", "--pipe", action="store_true", dest="pipe", default=False, help="print listings in xml suitable for obmenu") (options, args) = parser.parse_args() for entry in channellist: #check files are up to date if not os.path.exists(tmpfile % entry): downloader(address,channellistdict[entry],entry).start() if options.text: for entry in channellist: print "\n\033[01;04m%s\033[00;00m" % entry #print bold & underlined printer(entry).showplaintext() elif options.pipe : print "" print "" for entry in channellist: printer(entry).showxmlmenu() print ""