2010-08-29 19:20:13 +00:00
|
|
|
"""
|
|
|
|
TV information, written by Lurchington 2010
|
2010-08-30 02:12:03 +00:00
|
|
|
modified by rmmh 2010
|
2010-08-29 19:20:13 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
import datetime
|
2010-09-03 02:30:25 +00:00
|
|
|
from urllib2 import URLError
|
2010-09-09 02:22:25 +00:00
|
|
|
from zipfile import ZipFile
|
2010-09-11 02:23:17 +00:00
|
|
|
from cStringIO import StringIO
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-09-09 02:22:25 +00:00
|
|
|
from lxml import etree
|
2010-08-30 02:12:03 +00:00
|
|
|
from util import hook, http
|
2010-08-29 19:20:13 +00:00
|
|
|
|
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
base_url = "http://thetvdb.com/api/"
|
2010-09-03 02:30:25 +00:00
|
|
|
api_key = "469B73127CA0C411"
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-09-11 03:01:20 +00:00
|
|
|
|
2010-09-09 02:22:25 +00:00
|
|
|
def get_zipped_xml(*args, **kwargs):
|
|
|
|
try:
|
|
|
|
path = kwargs.pop("path")
|
|
|
|
except KeyError:
|
|
|
|
raise KeyError("must specify a path for the zipped file to be read")
|
2010-09-11 02:23:17 +00:00
|
|
|
zip_buffer = StringIO(http.get(*args, **kwargs))
|
|
|
|
return etree.parse(ZipFile(zip_buffer, "r").open(path))
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
def get_episodes_for_series(seriesname):
|
|
|
|
res = {"error":None, "ended":False, "episodes":None, "name":None}
|
2010-08-30 02:12:03 +00:00
|
|
|
# http://thetvdb.com/wiki/index.php/API:GetSeries
|
2010-09-03 02:30:25 +00:00
|
|
|
try:
|
2011-01-20 15:12:13 +00:00
|
|
|
query = http.get_xml(base_url + 'GetSeries.php', seriesname=seriesname)
|
2010-09-03 02:30:25 +00:00
|
|
|
except URLError:
|
2011-01-20 15:12:13 +00:00
|
|
|
res["error"]="error contacting thetvdb.com"
|
|
|
|
return res
|
2010-09-11 03:01:20 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
series_id = query.xpath('//seriesid/text()')
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
if not series_id:
|
2011-01-20 15:12:13 +00:00
|
|
|
res["error"] = "unknown tv series (using www.thetvdb.com)"
|
|
|
|
return res
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
series_id = series_id[0]
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-09-03 02:30:25 +00:00
|
|
|
try:
|
2010-09-09 02:22:25 +00:00
|
|
|
series = get_zipped_xml(base_url + '%s/series/%s/all/en.zip' %
|
|
|
|
(api_key, series_id), path="en.xml")
|
2010-09-11 03:01:20 +00:00
|
|
|
except URLError:
|
2011-01-20 15:12:13 +00:00
|
|
|
res["error"] = "error contacting thetvdb.com"
|
|
|
|
return res
|
2010-09-11 03:01:20 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
series_name = series.xpath('//SeriesName/text()')[0]
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
if series.xpath('//Status/text()')[0] == 'Ended':
|
2011-01-20 15:12:13 +00:00
|
|
|
res["ended"] = True
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
res["episodes"] = series.xpath('//Episode')
|
|
|
|
res["name"] = series_name
|
|
|
|
return res
|
|
|
|
|
|
|
|
def get_episode_info(episode):
|
|
|
|
first_aired = episode.findtext("FirstAired")
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
try:
|
|
|
|
airdate = datetime.date(*map(int, first_aired.split('-')))
|
|
|
|
except (ValueError, TypeError):
|
|
|
|
return None
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
episode_num = "S%02dE%02d" % (int(episode.findtext("SeasonNumber")),
|
|
|
|
int(episode.findtext("EpisodeNumber")))
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
episode_name = episode.findtext("EpisodeName")
|
|
|
|
# in the event of an unannounced episode title, users either leave the
|
|
|
|
# field out (None) or fill it with TBA
|
|
|
|
if episode_name == "TBA":
|
|
|
|
episode_name = None
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
episode_desc = '%s' % episode_num
|
|
|
|
if episode_name:
|
|
|
|
episode_desc += ' - %s' % episode_name
|
|
|
|
return (first_aired, airdate, episode_desc)
|
2010-08-29 19:20:13 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
@hook.command
|
|
|
|
@hook.command('tv')
|
|
|
|
def tv_next(inp):
|
|
|
|
".tv_next <series> -- get the next episode of <series> from thetvdb.com"
|
|
|
|
episodes = get_episodes_for_series(inp)
|
|
|
|
|
|
|
|
if episodes["error"]:
|
|
|
|
return episodes["error"]
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
series_name = episodes["name"]
|
|
|
|
ended = episodes["ended"]
|
|
|
|
episodes = episodes["episodes"]
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
if ended:
|
|
|
|
return "%s has ended." % series_name
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
next_eps = []
|
|
|
|
today = datetime.date.today()
|
2010-08-30 03:35:27 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
for episode in reversed(episodes):
|
2011-03-09 17:18:30 +00:00
|
|
|
ep_info = get_episode_info(episode)
|
|
|
|
|
|
|
|
if ep_info is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
(first_aired, airdate, episode_desc) = ep_info
|
2010-08-30 03:35:27 +00:00
|
|
|
|
2010-08-29 19:20:13 +00:00
|
|
|
if airdate > today:
|
2010-08-30 02:12:03 +00:00
|
|
|
next_eps = ['%s (%s)' % (first_aired, episode_desc)]
|
2010-08-29 19:20:13 +00:00
|
|
|
elif airdate == today:
|
2010-08-30 02:12:03 +00:00
|
|
|
next_eps = ['Today (%s)' % episode_desc] + next_eps
|
2010-08-29 19:20:13 +00:00
|
|
|
else:
|
|
|
|
#we're iterating in reverse order with newest episodes last
|
|
|
|
#so, as soon as we're past today, break out of loop
|
|
|
|
break
|
2010-08-30 03:35:27 +00:00
|
|
|
|
2010-08-29 19:20:13 +00:00
|
|
|
if not next_eps:
|
2010-08-30 02:12:03 +00:00
|
|
|
return "there are no new episodes scheduled for %s" % series_name
|
2010-08-30 03:35:27 +00:00
|
|
|
|
2010-08-30 02:12:03 +00:00
|
|
|
if len(next_eps) == 1:
|
|
|
|
return "the next episode of %s airs %s" % (series_name, next_eps[0])
|
2010-08-29 19:20:13 +00:00
|
|
|
else:
|
2010-08-30 03:35:27 +00:00
|
|
|
next_eps = ', '.join(next_eps)
|
|
|
|
return "the next episodes of %s: %s" % (series_name, next_eps)
|
2011-01-20 15:12:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@hook.command
|
|
|
|
@hook.command('tv_prev')
|
|
|
|
def tv_last(inp):
|
|
|
|
".tv_last <series> -- get the most recently aired episode of <series> from thetvdb.com"
|
|
|
|
episodes = get_episodes_for_series(inp)
|
|
|
|
|
|
|
|
if episodes["error"]:
|
|
|
|
return episodes["error"]
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
series_name = episodes["name"]
|
|
|
|
ended = episodes["ended"]
|
|
|
|
episodes = episodes["episodes"]
|
2011-03-09 17:18:30 +00:00
|
|
|
|
2011-01-20 15:12:13 +00:00
|
|
|
prev_ep = None
|
|
|
|
today = datetime.date.today()
|
|
|
|
|
|
|
|
for episode in reversed(episodes):
|
2011-03-09 17:18:30 +00:00
|
|
|
ep_info = get_episode_info(episode)
|
|
|
|
|
|
|
|
if ep_info is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
(first_aired, airdate, episode_desc) = ep_info
|
2011-01-20 15:12:13 +00:00
|
|
|
|
|
|
|
if airdate < today:
|
|
|
|
#iterating in reverse order, so the first episode encountered
|
|
|
|
#before today was the most recently aired
|
|
|
|
prev_ep = '%s (%s)' % (first_aired, episode_desc)
|
|
|
|
break
|
|
|
|
|
|
|
|
if not prev_ep:
|
|
|
|
return "there are no previously aired episodes for %s" % series_name
|
|
|
|
if ended:
|
|
|
|
return '%s has ended. The last episode aired %s' % (series_name, prev_ep)
|
|
|
|
return "the last episode of %s aired %s" % (series_name, prev_ep)
|