info = { 'author': 'Jon Bergli Heier', 'title': 'anidb', 'description': 'Fetches anime info from anidb.net.', } import urllib2, gzip, os, time import psycopg2 from xml import etree import pyanidb import ConfigParser import marshal anidb_cfg = {} cp = ConfigParser.ConfigParser() cp.read(os.path.expanduser('~/.pyanidb.conf')) for option in ('username', 'password'): anidb_cfg[option] = cp.get('pyanidb', option) class Module: def __init__(self, bot): self.irc = bot self.db = psycopg2.connect(database = 'fot') if self.irc: self.irc.register_keyword('!anidb', self) def get_aid(self, msg, short = False): if msg.isdigit(): return [(int(msg), 'N/A')] search = '%'.join(msg.split()) if not search: return if not short: search = '%%%s%%' % search cur = self.db.cursor() if short: cur.execute('select * from anidb a where aid in (select distinct aid from anidb where title ~~* %s and type in (2, 3)) and type = 1' 'order by (select hits from anidb_weights w where a.aid = w.aid)', (search,)) else: cur.execute('select * from anidb a where aid in (select distinct aid from anidb where title ~~* %s) and type = 1 ' 'order by (select hits from anidb_weights w where a.aid = w.aid)', (search,)) r = cur.fetchall() cur.close() return [(r[0][0], r[0][3])] if len(r) == 1 else [(x[0], x[3]) for x in r] def got_hit(self, aid): cur = self.db.cursor() cur.execute('update anidb_weights set hits = hits + 1 where aid = %s', (aid,)) # assume no hits yet if cur.rowcount == 0: cur.execute('insert into anidb_weights (aid, hits) values (%s, 1)', (aid,)) cur.close() self.db.commit() def get_info(self, aid): cachepath = os.path.expanduser('~/.fotanidbcache/a%d.dat' % aid) if os.access(cachepath, os.F_OK | os.R_OK) and time.time() - os.stat(cachepath).st_mtime < 60*60*24*7: cache = open(cachepath, 'r').read() data = marshal.loads(cache) else: amask = '33a0c0f0000080' try: anidb = pyanidb.AniDB(anidb_cfg['username'], anidb_cfg['password']) anidb.auth() data = anidb.get_anime(aid = aid, amask = amask) anidb.logout() open(cachepath, 'w').write(marshal.dumps(data)) except: return 'Failed to get data from anidb' year, type, catlist, catweight, romaji, english, epcount, normalep, rating, ratingcount, temprating, tempcount, specialep = data if '-' in year: syear, eyear = [int(x) if x.isdigit() else '' for x in year.split('-')] if syear == eyear: year = syear catlist = catlist.split(',') catweight = catweight.split(',') try: catn = max(catweight.index(str(int(catweight[0])-1)), 10) except: catn = 10 rating = float(rating) / 100 temprating = float(temprating) / 100 epcount = int(epcount) normalep = int(normalep) specialep = int(specialep) catl = ', '.join(catlist[:catn] + (['+%d more' % (len(catlist)-catn)] if len(catlist) > catn else [])) s = '%s%s is: %s, year %s, %d%s%s eps%s, cats: %s | rating: %.2f (%s), temp: %.2f (%s) | http://anidb.net/a%d' % ( romaji, ' aka. %s' % english if english else '', type, year, normalep, '/%d' % epcount if epcount > 0 and normalep != epcount else '', '+%d' % specialep if specialep > 0 else '', ' (ongoing)' if epcount == 0 or normalep < epcount else '', catl or '(None)', rating, ratingcount, temprating, tempcount, aid) return s.encode('utf8') def get_anime(self, msg): short = msg.startswith('-s') if short: msg = ' '.join(msg.split()[1:]) if not len(msg): return 'Usage: !anidb [-s] search|aid' aid = self.get_aid(msg, short) if len(aid) == 1: self.got_hit(aid[0][0]) return self.get_info(aid[0][0]) else: if len(aid) == 0: return 'anidb: No results' else: return 'anidb: %s%s' % ('%d/%d results: ' % (5, len(aid)) if len(aid) > 5 else '', ', '.join(['%s (%d)' % (x[1], x[0]) for x in aid[:5]])) def keyword(self, nick, channel, kw, msg): target = channel if not channel == self.irc.nickname else nick.split('!')[0] args = msg.split() if len(args) == 0: self.irc.msg(target, 'Usage: !anidb [-s] search|aid') return info = self.get_anime(' '.join(args)) if info: self.irc.msg(target, info) if __name__ == '__main__': import sys m = Module(None) print m.get_anime(' '.join(sys.argv[1:]))