Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!
Guest

Untitled

By: a guest on Feb 5th, 2011  |  syntax: Python  |  size: 10.95 KB  |  views: 375  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. #!/usr/bin/env python
  2. """
  3. tvcli
  4.  
  5. This is a command line program to manage your favourite TV programs and output air times/program names.
  6. This is the first project I've created in python, feedback is welcome.
  7.  
  8. Copyright (c) 2011
  9. """
  10.  
  11. import copy, getopt, os.path, pickle, urllib, sys, time
  12. from datetime import date, timedelta, datetime
  13. from xml.dom.minidom import parse, parseString
  14. from colorama import init, Fore, Back, Style
  15. init()
  16.  
  17. APIKEY = 'AB4A43DCDF3A99B5'
  18.  
  19. def updateAll():
  20.     shows = getData()
  21.     if not shows:
  22.         print "You have no favourite TV programs to update!"
  23.         return 1
  24.     for show in shows:
  25.         print "Updating episode list for "+show['SeriesName']+"..."
  26.         updateEpisodes(show['id'])
  27.  
  28. def getData():
  29.     if not os.path.isfile('data/favourites.pk'):
  30.         return 0
  31.     f = open('data/favourites.pk','r')
  32.     data = pickle.load(f)
  33.     f.close()
  34.     return data
  35.  
  36. def getEpData(pID):
  37.     if not os.path.isfile('data/episodes/'+pID+'.pk'):
  38.         return 0
  39.     f = open('data/episodes/'+pID+'.pk','r')
  40.     data = pickle.load(f)
  41.     f.close()
  42.     return data
  43.  
  44. def listProgs(favs):
  45.     if not favs:
  46.         print "Your favourites list is empty :("
  47.         return 1
  48.     for i in range(len(favs)):
  49.         print Fore.CYAN+Style.BRIGHT+`i+1`+': '+Style.RESET_ALL+favs[i]['SeriesName']
  50.     return 0
  51.  
  52. def getNextEp(pID):
  53.     episodes = getEpData(pID)
  54.    
  55.     d = date.today()
  56.  
  57.     airDate = d.isoformat()
  58.     offset = -99999999
  59.     for episode in episodes:
  60.         if 'FirstAired' in episode:
  61.             o = int(airDate.replace('-','')) - int(episode['FirstAired'].replace('-',''))
  62.             if o < 0 and o > offset:
  63.                 offset = o
  64.                 airDate = episode['FirstAired']
  65.                 epName = "["+episode['SeasonNumber']+"x"+episode['EpisodeNumber']+"] "+episode['EpisodeName']
  66.     try:
  67.         epName
  68.     except NameError:
  69.         epName = None
  70.  
  71.     if epName == None:
  72.         return "No data available."
  73.     else:
  74.         return date.fromtimestamp(time.mktime(time.strptime(airDate,"%Y-%m-%d"))).strftime("%d %B %Y")+" - "+epName
  75.  
  76. def showToday():
  77.     today = date.today().strftime("%d %B %Y")
  78.     d = getData()
  79.  
  80.     programs = []
  81.  
  82.     for i in range(len(d)):
  83.         p = d[i]
  84.         n = getNextEp(p['id'])
  85.         if n.find(today) > -1:
  86.             p['cid'] = i
  87.             programs.append(p)
  88.    
  89.     if len(programs)==0:
  90.         print "No programs airing today."
  91.         return 1
  92.    
  93.     print Fore.CYAN+Style.BRIGHT+"Airing Today:"+Style.RESET_ALL
  94.  
  95.     for p in programs:
  96.         info(p['cid']+1)
  97.  
  98. def showTomorrow():
  99.     t = date.today()+timedelta(days=2)
  100.     tomorrow = t.strftime("%d %B %Y")
  101.     d = getData()
  102.  
  103.     programs = []
  104.  
  105.     for i in range(len(d)):
  106.         p = d[i]
  107.         n = getNextEp(p['id'])
  108.         if n.find(tomorrow) > -1:
  109.             p['cid'] = i
  110.             programs.append(p)
  111.    
  112.     if len(programs)==0:
  113.         print "No programs airing tomorrow."
  114.         return 1
  115.    
  116.     print Fore.CYAN+Style.BRIGHT+"Airing Tomorrow:"+Style.RESET_ALL
  117.  
  118.     for p in programs:
  119.         info(p['cid']+1)
  120.  
  121. def showInDays(days):
  122.     td = date.today().isoformat()
  123.     d = getData()
  124.    
  125.     days = int(days)
  126.  
  127.     progs = []
  128.  
  129.     for i in range(len(d)):
  130.         p = d[i]
  131.         episodes = getEpData(p['id'])
  132.         for episode in episodes:
  133.             if 'FirstAired' in episode:
  134.                 o = int(episode['FirstAired'].replace('-','')) - int(td.replace('-',''))
  135.                 if o <= days and o > 0:
  136.                     p['cid'] = i
  137.                     progs.append(p)
  138.     if len(progs)==0:
  139.         print "No programs airing in the next "+`days`+" days."
  140.         return 1
  141.    
  142.     print Fore.CYAN+Style.BRIGHT+"Airing in the next "+`days`+" Days:"+Style.RESET_ALL
  143.  
  144.     for p in progs:
  145.         info(p['cid']+1)
  146.  
  147.  
  148. def getLastEp(pID):
  149.     episodes = getEpData(pID)
  150.    
  151.     d = date.today()
  152.  
  153.     now = d.isoformat()
  154.     for episode in episodes:
  155.         if 'FirstAired' in episode:
  156.             o = int(now.replace('-','')) - int(episode['FirstAired'].replace('-',''))
  157.             try:
  158.                 offset
  159.             except NameError:
  160.                 offset = o
  161.             if o > 0 and o < offset:
  162.                 offset = o
  163.                 airDate = episode['FirstAired']
  164.                 epName = "["+episode['SeasonNumber']+"x"+episode['EpisodeNumber']+"] "+episode['EpisodeName']
  165.     try:
  166.         airDate
  167.     except NameError:
  168.         airDate = None
  169.     if airDate == None:
  170.         return "No data available."
  171.     else:
  172.         return date.fromtimestamp(time.mktime(time.strptime(airDate,"%Y-%m-%d"))).strftime("%d %B %Y")+" - "+epName
  173.  
  174. def search(program):
  175.     sock = urllib.urlopen("http://www.thetvdb.com/api/GetSeries.php?seriesname="+program)
  176.     f = sock.read()
  177.     sock.close()
  178.     dom = parseString(f)
  179.    
  180.     if len(dom.getElementsByTagName('Series')) == 0:
  181.         print "No episodes found with that name."
  182.         return 1
  183.    
  184.     for series in dom.getElementsByTagName('Series'):
  185.         name = series.getElementsByTagName('SeriesName')
  186.         ID = series.getElementsByTagName('seriesid')
  187.         fa = series.getElementsByTagName('FirstAired')
  188.         overview = series.getElementsByTagName('Overview')
  189.  
  190.         if len(name) < 0:
  191.             break
  192.  
  193.         s = getSeriesData(ID[0].childNodes[0].data)
  194.  
  195.         print "\n"+Style.BRIGHT+Fore.BLUE+ID[0].childNodes[0].data+" - "+name[0].childNodes[0].data+Style.RESET_ALL
  196.         if len(overview) > 0:
  197.             print Style.BRIGHT+"   Overview:\t"+Style.NORMAL+overview[0].childNodes[0].data[:60].rsplit(' ',1)[0]+"..."
  198.         if len(fa) > 0:
  199.             print Style.BRIGHT+"   First Aired:\t"+Style.NORMAL+date.fromtimestamp(time.mktime(time.strptime(fa[0].childNodes[0].data,"%Y-%m-%d"))).strftime("%d %B %Y")
  200.         if 'Genre' in s:
  201.             genres = s['Genre'].split('|')
  202.             print Style.BRIGHT+"   Genre(s):\t"+Style.NORMAL,
  203.             for i in range(len(genres)):
  204.                 genre = genres[i]
  205.                 if len(genre.strip()) > 0:
  206.                     sys.stdout.write(genre)
  207.                     if len(genres) != (i+2):
  208.                         print ", ",
  209.             print
  210.         if 'Network' in s:
  211.             print Style.BRIGHT+"   Network:\t"+Style.NORMAL+s['Network']
  212.         if 'Rating' in s:
  213.             print Style.BRIGHT+"   Rating:\t"+Style.NORMAL+s['Rating']
  214.         if 'Status' in s:
  215.             print Style.BRIGHT+"   Status:\t"+Style.NORMAL+s['Status']
  216.  
  217. def updateEpisodes(pID):
  218.     url = "http://www.thetvdb.com/api/"+APIKEY+"/series/"+pID+"/all"
  219.     sock = urllib.urlopen(url)
  220.     if sock.getcode() == 200:
  221.         f = sock.read()
  222.     else:
  223.         return 1
  224.     sock.close()
  225.     dom = parseString(f)
  226.  
  227.     episode = {}
  228.     episodes = []
  229.  
  230.     for episodeData in dom.getElementsByTagName('Episode'):
  231.         for tag in episodeData.childNodes:
  232.             if tag.nodeName != "#text" and tag.nodeValue !="\n":
  233.                 if len(tag.childNodes) > 0:
  234.                     episode[tag.nodeName] = tag.childNodes[0].data
  235.         episodes.append(episode.copy())
  236.         episode.clear()
  237.  
  238.     f = open('data/episodes/'+pID+'.pk','w')
  239.     pickle.dump(episodes,f)
  240.     f.close()
  241.  
  242. def delete(pID):
  243.     d = getData()
  244.     print Style.BRIGHT+"Are you sure you want to delete "+d[int(pID)-1]['SeriesName']+"?"+Style.NORMAL
  245.     i = raw_input('(y/n): ')
  246.     if i == "n" or i=="N":
  247.         print "Quitting..."
  248.         sys.exit(1)
  249.     elif i!="y" and i!="Y":
  250.         print "Invalid."
  251.         sys.exit(1)
  252.     del d[int(pID)-1]
  253.     f = open('data/favourites.pk','w')
  254.     pickle.dump(d,f)
  255.     f.close()
  256.     print "Deleted."
  257.  
  258. def getSeriesData(pID):
  259.     url = "http://www.thetvdb.com/api/"+APIKEY+"/series/"+pID+"/all"
  260.     sock = urllib.urlopen(url)
  261.     if sock.getcode() == 200:
  262.         f = sock.read()
  263.     else:
  264.         print "Error: Series not found or API key incorrect."
  265.         return 1
  266.     sock.close()
  267.     dom = parseString(f)
  268.    
  269.     prog = {}
  270.  
  271.     for sInfo in dom.getElementsByTagName('Series'):
  272.         for tag in sInfo.childNodes:
  273.             if tag.nodeName != "#text" and tag.nodeValue != "\n":
  274.                 if len(tag.childNodes) > 0:
  275.                     prog[tag.nodeName] = tag.childNodes[0].data
  276.     return prog
  277.  
  278.  
  279. def add(pID):
  280.     print "Searching for "+pID+" in the TVDB..."
  281.    
  282.     prog = getSeriesData(pID)
  283.  
  284.     progs = []
  285.     if os.path.isfile('data/favourites.pk'):
  286.         current = getData()
  287.         current.append(prog)
  288.         progs = current
  289.     else:
  290.         progs = [ prog ]
  291.  
  292.     f = open('data/favourites.pk','w')
  293.     pickle.dump(progs,f)
  294.     f.close()
  295.  
  296.     print "Added "+prog['SeriesName']+" to favourites."
  297.     print "Updating episodes..."
  298.     updateEpisodes(pID)
  299.     print "Done"
  300.  
  301. def info(fID):
  302.     fID = int(fID)-1
  303.  
  304.     d = getData()
  305.  
  306.     if len(d) < fID:
  307.         print "Bad program ID. Please use the ID for the program given by the --list option."
  308.         sys.exit(1)
  309.  
  310.     program = d[fID]
  311.  
  312.     print Fore.BLUE+Style.BRIGHT+`fID+1`+": "+program['SeriesName']+Style.RESET_ALL
  313.     print Style.BRIGHT+"  Airs: "+Style.NORMAL+program['Airs_DayOfWeek']+"s "+program['Airs_Time']+" (Network's local time)"
  314.     print Style.BRIGHT+"  Latest Episode: "+Style.NORMAL+getLastEp(program['id'])
  315.     print Style.BRIGHT+"  Next Episode: "+Style.NORMAL+getNextEp(program['id'])
  316.  
  317. def usage():
  318.     print "Usage: tvcli <action>"
  319.     print "   -s,\t--search=PROGRAM\tSearch for a program's ID in the TvDB."
  320.     print "   -i,\t--info=PID\t\tRetrive info for program using ID (from --list)"
  321.     print "   -a,\t--add=TVDBID\t\tAdd program (identified by TvDB ID) to favourites list."
  322.     print "   -d,\t--days=NUM\t\tList programs airing in the next NUM days."
  323.     print "   -t,\t--today\t\t\tList programs airing today."
  324.     print "   -T,\t--tomorrow\t\tList programs airing tomorrow."
  325.     print "   -u,\t--update\t\tUpdate episode lists."
  326.     print "   -l,\t--list\t\t\tList the programs being tracked."
  327.     print "   -D,\t--delete=PID\t\tDelete a program using ID from --list."
  328.  
  329. def main(argv):
  330.  
  331.     if len(argv) == 0:
  332.         usage()
  333.         sys.exit(1)
  334.  
  335.     try:
  336.         opts, args = getopt.getopt(argv, "s:i:a:d:D:tTul", ["search=","info=","add=","days=","delete=","today","tomorrow","update","list"])
  337.  
  338.     except getopt.GetoptError:
  339.         usage()
  340.         sys.exit(2)
  341.  
  342.     for o, a in opts:
  343.         if o in ("-l", "--list"):
  344.             listProgs(getData())
  345.         if o in ("-s", "--search"):
  346.             search(a)
  347.         if o in ("-u", "--update"):
  348.             updateAll()
  349.         if o in ("-a", "--add"):
  350.             add(a)
  351.         if o in ("-i", "--info"):
  352.             info(a)
  353.         if o in ("-D", "--delete"):
  354.             delete(a)
  355.         if o in ("-t", "--today"):
  356.             showToday()
  357.         if o in ("-T", "--tomorrow"):
  358.             showTomorrow()
  359.         if o in ("-d", "--days"):
  360.             showInDays(a)
  361.  
  362. main(sys.argv[1:])