diff --git a/bot.py b/bot.py index b9de4cc..1bcc46b 100755 --- a/bot.py +++ b/bot.py @@ -9,6 +9,7 @@ import os import Queue sys.path += ['plugins'] # so 'import hook' works without duplication +sys.path += ['lib'] os.chdir(sys.path[0]) # do stuff relative to the installation directory import irc diff --git a/lib/timesince.py b/lib/timesince.py new file mode 100644 index 0000000..03e8802 --- /dev/null +++ b/lib/timesince.py @@ -0,0 +1,96 @@ +# Copyright (c) Django Software Foundation and individual contributors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of Django nor the names of its contributors may be used +# to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import datetime +import time + +def timesince(d, now=None): + """ + Takes two datetime objects and returns the time between d and now + as a nicely formatted string, e.g. "10 minutes". If d occurs after now, + then "0 minutes" is returned. + + Units used are years, months, weeks, days, hours, and minutes. + Seconds and microseconds are ignored. Up to two adjacent units will be + displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are + possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not. + + Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since + """ + chunks = ( + (60 * 60 * 24 * 365, ('year', 'years')), + (60 * 60 * 24 * 30, ('month', 'months')), + (60 * 60 * 24 * 7, ('week', 'weeks')), + (60 * 60 * 24, ('day', 'days')), + (60 * 60, ('hour', 'hours')), + (60, ('minute', 'minutes')) + ) + # Convert datetime.date to datetime.datetime for comparison. + if not isinstance(d, datetime.datetime): + d = datetime.datetime(d.year, d.month, d.day) + if now and not isinstance(now, datetime.datetime): + now = datetime.datetime(now.year, now.month, now.day) + + if not now: + now = datetime.datetime.now() + + # ignore microsecond part of 'd' since we removed it from 'now' + delta = now - (d - datetime.timedelta(0, 0, d.microsecond)) + since = delta.days * 24 * 60 * 60 + delta.seconds + if since <= 0: + # d is in the future compared to now, stop processing. + return u'0 ' + 'minutes' + for i, (seconds, name) in enumerate(chunks): + count = since // seconds + if count != 0: + break + + if count == 1: + s = '%(number)d %(type)s' % {'number': count, 'type': name[0]} + else: + s = '%(number)d %(type)s' % {'number': count, 'type': name[1]} + + if i + 1 < len(chunks): + # Now get the second item + seconds2, name2 = chunks[i + 1] + count2 = (since - (seconds * count)) // seconds2 + if count2 != 0: + if count2 == 1: + s += ', %(number)d %(type)s' % {'number': count2, 'type': name2[0]} + else: + s += ', %(number)d %(type)s' % {'number': count2, 'type': name2[1]} + return s + +def timeuntil(d, now=None): + """ + Like timesince, but returns a string measuring the time until + the given time. + """ + if not now: + now = datetime.datetime.now() + return timesince(now, d) diff --git a/plugins/seen.py b/plugins/seen.py index 0f58df0..788d2e4 100644 --- a/plugins/seen.py +++ b/plugins/seen.py @@ -4,6 +4,7 @@ import sqlite3 import datetime, time import hook import os +from timesince import timesince dbname = "skydb" @@ -32,7 +33,6 @@ def seeninput(bot,input): conn.commit() conn.close() - @hook.command def seen(bot, input): ".seen - Tell when a nickname was last in active in irc" @@ -40,7 +40,6 @@ def seen(bot, input): if len(input.msg) < 6: return seen.__doc__ - query = input.msg[6:].strip() if query == input.nick: @@ -57,11 +56,11 @@ def seen(bot, input): conn.close() if(results != None): - date = time.gmtime(results[0]) - quote = results[1] - return time.strftime(query+" was last seen %a %Y-%m-%d %I:%M:%S %p GMT saying: \"<"+query+"> "+quote+"\"", date) + reltime = timesince(datetime.datetime.fromtimestamp(results[0])) + return '%(name)s was last seen %(timespan)s ago saying: <%(name)s> %(quote)s' % \ + {'name': query, 'timespan': reltime, 'quote': results[1]} else: - return "I've never seen "+query + return "I've never seen %(name)s" % {'name':query} # check to see that our db has the the seen table, and return a connection.