h/plugins/tvdb.py

166 lines
4.8 KiB
Python
Raw Normal View History

"""
TV information, written by Lurchington 2010
modified by rmmh 2010
"""
import datetime
from urllib2 import URLError
from zipfile import ZipFile
from cStringIO import StringIO
from lxml import etree
from util import hook, http, timesince
base_url = "http://thetvdb.com/api/"
api_key = "469B73127CA0C411"
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")
zip_buffer = StringIO(http.get(*args, **kwargs))
return etree.parse(ZipFile(zip_buffer, "r").open(path))
2011-05-11 20:40:04 +00:00
2011-01-20 15:12:13 +00:00
def get_episodes_for_series(seriesname):
2011-05-11 20:40:04 +00:00
res = {"error": None, "ended": False, "episodes": None, "name": None}
# http://thetvdb.com/wiki/index.php/API:GetSeries
try:
2011-01-20 15:12:13 +00:00
query = http.get_xml(base_url + 'GetSeries.php', seriesname=seriesname)
except URLError:
2011-05-11 20:40:04 +00:00
res["error"] = "error contacting thetvdb.com"
2011-01-20 15:12:13 +00:00
return res
series_id = query.xpath('//seriesid/text()')
if not series_id:
2011-01-20 15:12:13 +00:00
res["error"] = "unknown tv series (using www.thetvdb.com)"
return res
series_id = series_id[0]
try:
series = get_zipped_xml(base_url + '%s/series/%s/all/en.zip' %
(api_key, series_id), path="en.xml")
except URLError:
2011-01-20 15:12:13 +00:00
res["error"] = "error contacting thetvdb.com"
return res
series_name = series.xpath('//SeriesName/text()')[0]
if series.xpath('//Status/text()')[0] == 'Ended':
2011-01-20 15:12:13 +00:00
res["ended"] = True
2011-01-20 15:12:13 +00:00
res["episodes"] = series.xpath('//Episode')
res["name"] = series_name
return res
2011-05-11 20:40:04 +00:00
2011-01-20 15:12:13 +00:00
def get_episode_info(episode):
episode_air_date = episode.findtext("FirstAired")
2011-01-20 15:12:13 +00:00
try:
airdate = datetime.date(*map(int, episode_air_date.split('-')))
2011-01-20 15:12:13 +00:00
except (ValueError, TypeError):
return None
2011-01-20 15:12:13 +00:00
episode_num = "S%02dE%02d" % (int(episode.findtext("SeasonNumber")),
int(episode.findtext("EpisodeNumber")))
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-01-20 15:12:13 +00:00
episode_desc = '%s' % episode_num
if episode_name:
episode_desc += ' - %s' % episode_name
return (episode_air_date, airdate, episode_desc)
2011-05-11 20:40:04 +00:00
2011-01-20 15:12:13 +00:00
@hook.command
@hook.command('tv')
def tv_next(inp):
2011-05-11 20:40:04 +00:00
".tv_next <series> -- get the next episode of <series>"
2011-01-20 15:12:13 +00:00
episodes = get_episodes_for_series(inp)
if episodes["error"]:
return episodes["error"]
2011-01-20 15:12:13 +00:00
series_name = episodes["name"]
ended = episodes["ended"]
episodes = episodes["episodes"]
2011-01-20 15:12:13 +00:00
if ended:
return "%s has ended." % series_name
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):
ep_info = get_episode_info(episode)
if ep_info is None:
continue
(episode_air_date, airdate, episode_desc) = ep_info
2010-08-30 03:35:27 +00:00
if airdate > today:
next_eps = ['%s (%s) (%s)' % (episode_air_date, timesince.timeuntil(datetime.datetime.strptime(episode_air_date, "%Y-%m-%d")), episode_desc)]
elif airdate == today:
next_eps = ['Today (%s)' % episode_desc] + next_eps
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
if not next_eps:
return "there are no new episodes scheduled for %s" % series_name
2010-08-30 03:35:27 +00:00
if len(next_eps) == 1:
return "the next episode of %s airs %s" % (series_name, next_eps[0])
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):
2011-05-11 20:40:04 +00:00
".tv_last <series> -- gets the most recently aired episode of <series>"
2011-01-20 15:12:13 +00:00
episodes = get_episodes_for_series(inp)
if episodes["error"]:
return episodes["error"]
2011-01-20 15:12:13 +00:00
series_name = episodes["name"]
ended = episodes["ended"]
episodes = episodes["episodes"]
2011-04-14 01:45:07 +00:00
prev_ep = None
2011-01-20 15:12:13 +00:00
today = datetime.date.today()
for episode in reversed(episodes):
ep_info = get_episode_info(episode)
if ep_info is None:
continue
(episode_air_date, 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)' % (episode_air_date, episode_desc)
2011-01-20 15:12:13 +00:00
break
if not prev_ep:
return "there are no previously aired episodes for %s" % series_name
if ended:
2011-05-11 20:40:04 +00:00
return '%s ended. The last episode aired %s' % (series_name, prev_ep)
2011-01-20 15:12:13 +00:00
return "the last episode of %s aired %s" % (series_name, prev_ep)