This repository has been archived on 2023-04-13. You can view files and clone it, but cannot push or open issues or pull requests.
CloudBot/plugins/twitter.py

167 lines
5.3 KiB
Python
Raw Normal View History

2012-04-02 18:17:55 +02:00
# written by Scaevolus, modified by Lukeroge
2011-11-20 10:23:31 +01:00
import random
import re
2012-04-02 18:17:55 +02:00
from time import strftime
from time import strptime
2012-02-25 14:32:48 +01:00
from datetime import datetime
2012-04-02 18:17:55 +02:00
from util import hook
from util import http
from util import timesince
2011-11-20 10:23:31 +01:00
def unescape_xml(string):
2012-04-02 18:17:55 +02:00
"""Unescapes XML"""
2011-11-20 10:23:31 +01:00
return string.replace('&gt;', '>').replace('&lt;', '<').replace('&apos;',
"'").replace('&quote;', '"').replace('&amp;', '&')
history = []
history_max_size = 250
2012-03-23 01:32:48 +01:00
2012-02-25 14:32:48 +01:00
def parseDateTime(s):
2012-04-02 18:17:55 +02:00
"""Parses the date from a string"""
2012-02-29 09:29:53 +01:00
if s is None:
return None
m = re.match(r'(.*?)(?:\.(\d+))?(([-+]\d{1,2}):(\d{2}))?$',
str(s))
datestr, fractional, tzname, tzhour, tzmin = m.groups()
if tzname is None:
tz = None
else:
tzhour, tzmin = int(tzhour), int(tzmin)
if tzhour == tzmin == 0:
tzname = 'UTC'
tz = FixedOffset(timedelta(hours=tzhour,
minutes=tzmin), tzname)
2012-03-23 01:32:48 +01:00
2012-02-29 09:29:53 +01:00
x = datetime.strptime(datestr, "%Y-%m-%d %H:%M:%S")
if fractional is None:
fractional = '0'
fracpower = 6 - len(fractional)
fractional = float(fractional) * (10 ** fracpower)
return x.replace(microsecond=int(fractional), tzinfo=tz)
2012-02-25 14:32:48 +01:00
2011-11-20 10:23:31 +01:00
@hook.command
def twitter(inp):
2012-02-28 03:03:43 +01:00
".twitter <user>/<user> <n>/<id>/#<hashtag>/@<user> -- Gets last/<n>th "\
"tweet from <user>/gets tweet <id>/Gets random tweet with #<hashtag>/"\
"gets replied tweet from @<user>."
2011-11-20 10:23:31 +01:00
def add_reply(reply_name, reply_id):
if len(history) == history_max_size:
history.pop()
history.insert(0, (reply_name, reply_id))
def find_reply(reply_name):
for name, id in history:
if name == reply_name:
return id if id != -1 else name
if inp[0] == '@':
reply_inp = find_reply(inp[1:])
if reply_inp == None:
2012-02-25 14:32:48 +01:00
return 'No replies to %s found.' % inp
2011-11-20 10:23:31 +01:00
inp = reply_inp
url = 'http://api.twitter.com'
2011-11-20 10:23:31 +01:00
getting_nth = False
getting_id = False
searching_hashtag = False
time = 'status/created_at'
text = 'status/text'
retweeted_text = 'status/retweeted_status/text'
retweeted_screen_name = 'status/retweeted_status/user/screen_name'
2011-11-20 10:23:31 +01:00
reply_name = 'status/in_reply_to_screen_name'
reply_id = 'status/in_reply_to_status_id'
reply_user = 'status/in_reply_to_user_id'
if re.match(r'^\d+$', inp):
getting_id = True
url += '/statuses/show/%s.xml' % inp
screen_name = 'user/screen_name'
time = 'created_at'
text = 'text'
reply_name = 'in_reply_to_screen_name'
reply_id = 'in_reply_to_status_id'
reply_user = 'in_reply_to_user_id'
elif re.match(r'^\w{1,15}$', inp) or re.match(r'^\w{1,15}\s+\d+$', inp):
2011-11-20 10:23:31 +01:00
getting_nth = True
if inp.find(' ') == -1:
name = inp
num = 1
else:
name, num = inp.split()
2011-11-20 10:23:31 +01:00
if int(num) > 3200:
return 'error: only supports up to the 3200th tweet'
url += ('/1/statuses/user_timeline.xml?include_rts=true&'
'screen_name=%s&count=1&page=%s' % (name, num))
2011-11-20 10:23:31 +01:00
screen_name = 'status/user/screen_name'
elif re.match(r'^#\w+$', inp):
url = 'http://search.twitter.com/search.atom?q=%23' + inp[1:]
searching_hashtag = True
else:
return 'error: invalid request'
try:
tweet = http.get_xml(url)
except http.HTTPError, e:
errors = {400: 'bad request (ratelimited?)',
401: 'tweet is private',
403: 'tweet is private',
404: 'invalid user/id',
500: 'twitter is broken',
502: 'twitter is down ("getting upgraded")',
503: 'twitter is overloaded (lol, RoR)'}
if e.code == 404:
return 'error: invalid ' + ['username', 'tweet id'][getting_id]
if e.code in errors:
return 'error: ' + errors[e.code]
return 'error: unknown %s' % e.code
except http.URLError, e:
2011-11-20 10:23:31 +01:00
return 'error: timeout'
if searching_hashtag:
ns = '{http://www.w3.org/2005/Atom}'
tweets = tweet.findall(ns + 'entry/' + ns + 'id')
if not tweets:
2012-02-25 14:32:48 +01:00
return 'Hashtag not found!'
2011-11-20 10:23:31 +01:00
id = random.choice(tweets).text
id = id[id.rfind(':') + 1:]
return twitter(id)
if getting_nth:
if tweet.find('status') is None:
return "User doesn't have that many tweets!"
2011-11-20 10:23:31 +01:00
time = tweet.find(time)
if time is None:
return "User has no tweets!"
2011-11-20 10:23:31 +01:00
reply_name = tweet.find(reply_name).text
reply_id = tweet.find(reply_id).text
reply_user = tweet.find(reply_user).text
if reply_name is not None and (reply_id is not None or
reply_user is not None):
add_reply(reply_name, reply_id or -1)
2012-02-25 14:32:48 +01:00
time_raw = strftime('%Y-%m-%d %H:%M:%S',
2011-11-20 10:23:31 +01:00
strptime(time.text,
'%a %b %d %H:%M:%S +0000 %Y'))
2012-02-25 14:32:48 +01:00
2012-03-23 01:32:48 +01:00
time_nice = timesince.timesince(parseDateTime(time_raw), datetime.utcnow())
2012-02-25 14:32:48 +01:00
if tweet.find(retweeted_text) is not None:
text = 'RT @%s:' % tweet.find(retweeted_screen_name).text
text += unescape_xml(tweet.find(retweeted_text).text.replace('\n', ''))
else:
text = unescape_xml(tweet.find(text).text.replace('\n', ''))
2011-11-20 10:23:31 +01:00
screen_name = tweet.find(screen_name).text
2012-03-23 01:32:48 +01:00
return "\x02@%s\x02: %s (%s ago)" % (screen_name, text, time_nice)