Update some stuff in plugin. Update copyrights and ids.
This commit is contained in:
parent
d46967e339
commit
683cd3861b
53
README.md
53
README.md
|
|
@ -3,15 +3,26 @@ Supybot-Tweety
|
|||
|
||||
# Twitter client for Supybot
|
||||
|
||||
Description
|
||||
Description
|
||||
-----------
|
||||
|
||||
This is a supybot client.
|
||||
This is a Supybot plugin to work with Twitter. It allows a user to search for Tweets,
|
||||
display specific tweets and timelines from a user's account, and display Trends.
|
||||
|
||||
It has been updated to work with the oAuth requirement in v1.1 API along with their
|
||||
updated endpoints.
|
||||
|
||||
For working v1.1 API clients, I am aware of only this and ProgVal's Twitter client.
|
||||
This is a much watered down version of ProgVal's Twitter client. It only includes
|
||||
read-only features (no risk of accidental Tweeting) that most folks use:
|
||||
tweet display, tweet searching and trends.
|
||||
|
||||
Instructions
|
||||
------------
|
||||
1.) Install the dependencies. You can go the pip route or install via source, depending on your setup. You will need:
|
||||
1. Install oauth2: sudo pip install oauth2
|
||||
|
||||
1.) On an up-to-date Python 2.7+ system, one dependency is needed.
|
||||
You can go the pip route or install via source, depending on your setup. You will need:
|
||||
1. Install oauth2: pip install oauth2
|
||||
|
||||
2.) You need some keys from Twitter. See http://dev.twitter.com. Steps are:
|
||||
1. If you plan to use a dedicated Twitter account, create a new twitter account.
|
||||
2. Go to dev.twitter.com and log in.
|
||||
|
|
@ -19,15 +30,33 @@ Instructions
|
|||
4. Fill out the information. Name does not matter.
|
||||
5. default is read-only. Since we're not tweeting from this bot/code, you're fine here.
|
||||
6. Your 4 magic strings (2 tokens and 2 secrets) are shown.
|
||||
7. Once you /msg yourbot load Tweety, you need to set these keys:
|
||||
/msg bot config plugins.Tweety.consumer_key xxxxx
|
||||
/msg bot config plugins.Tweety.consumer_secret xxxxx
|
||||
/msg bot config plugins.Tweety.access_key xxxxx
|
||||
/msg bot config plugins.Tweety.access_secret xxxxx
|
||||
7. Once you /msg <bot> load Tweety, you need to set these keys:
|
||||
* /msg <bot> config plugins.Tweety.consumerKey xxxxx
|
||||
* /msg <bot> config plugins.Tweety.consumerSecret xxxxx
|
||||
* /msg <bot> config plugins.Tweety.accessKey xxxxx
|
||||
* /msg <bot> config plugins.Tweety.accessSecret xxxxx
|
||||
8. Next, I suggest you /msg <bot> config search Tweety. There are a lot of options here.
|
||||
9. Things should work fine from here providing your keys are right.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
# Documentation
|
||||
Background
|
||||
----------
|
||||
Hoaas, on GitHub, started this plugin with basics for Twitter and I started to submit
|
||||
ideas and code. After a bit, the plugin was mature but Twitter, in 2012, put out the
|
||||
notice that everything was changing with their move to v1.1 of the API. The client had
|
||||
no oAuth code, was independent of any Python library, so it needed a major rewrite. I
|
||||
decided to take this part on, using chunks of code from an oAuth/Twitter wrapper and
|
||||
later rewriting/refactoring many of the existing functions with the massive structural
|
||||
changes.
|
||||
|
||||
|
||||
So, as I take over, I must acknowledge the work done by Hoaas:
|
||||
http://github.com/Hoaas/
|
||||
Much/almost all of the oAuth code ideas came from:
|
||||
https://github.com/jpittman/OAuth-Python-Twitter
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
* https://dev.twitter.com/docs/api/1.1
|
||||
|
|
|
|||
29
__init__.py
29
__init__.py
|
|
@ -1,32 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###
|
||||
# Copyright (c) 2011-2013, Terje Hoås, spline
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Copyright (c) 2013, spline
|
||||
###
|
||||
|
||||
"""
|
||||
|
|
|
|||
30
config.py
30
config.py
|
|
@ -1,32 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###
|
||||
# Copyright (c) 2011-2013, Terje Hoås-spline
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Copyright (c) 2013, spline
|
||||
###
|
||||
|
||||
import supybot.conf as conf
|
||||
|
|
@ -56,5 +29,4 @@ conf.registerChannelValue(Tweety,'maxResults',registry.Integer(10, """Maximum nu
|
|||
conf.registerChannelValue(Tweety,'outputColorTweets',registry.Boolean(False, """When outputting Tweets, display them with some color."""))
|
||||
conf.registerChannelValue(Tweety,'hideHashtagsTrends',registry.Boolean(False, """When displaying trends, should we display #hashtags? Default is no."""))
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=250:
|
||||
|
|
|
|||
95
plugin.py
95
plugin.py
|
|
@ -1,32 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###
|
||||
# Copyright (c) 2011-2013, Terje Hoås, spline
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Copyright (c) 2013, spline
|
||||
###
|
||||
|
||||
# my libs
|
||||
|
|
@ -43,8 +16,7 @@ import unicodedata
|
|||
# oauthtwitter
|
||||
import urlparse
|
||||
import oauth2 as oauth
|
||||
|
||||
#supybot libs
|
||||
# supybot libs
|
||||
import supybot.utils as utils
|
||||
from supybot.commands import *
|
||||
import supybot.plugins as plugins
|
||||
|
|
@ -52,9 +24,8 @@ import supybot.ircutils as ircutils
|
|||
import supybot.callbacks as callbacks
|
||||
|
||||
|
||||
# OAuthApi class from https://github.com/jpittman/OAuth-Python-Twitter
|
||||
# mainly kept intact but modified for Twitter API v1.1 and unncessary things removed.
|
||||
class OAuthApi:
|
||||
""" OAuth class to work with Twitter v1.1 API."""
|
||||
def __init__(self, consumer_key, consumer_secret, token=None, token_secret=None):
|
||||
if token and token_secret:
|
||||
token = oauth.Token(token, token_secret)
|
||||
|
|
@ -64,20 +35,19 @@ class OAuthApi:
|
|||
self._signature_method = oauth.SignatureMethod_HMAC_SHA1()
|
||||
self._access_token = token
|
||||
|
||||
def _FetchUrl(self,url, http_method=None, parameters=None):
|
||||
def _FetchUrl(self,url, parameters=None):
|
||||
extra_params = {}
|
||||
if parameters:
|
||||
extra_params.update(parameters)
|
||||
|
||||
req = self._makeOAuthRequest(url, params=extra_params, http_method=http_method)
|
||||
req = self._makeOAuthRequest(url, params=extra_params)
|
||||
opener = urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1))
|
||||
url = req.to_url()
|
||||
#callbacks.log.info(str(url))
|
||||
url_data = opener.open(url).read()
|
||||
opener.close()
|
||||
return url_data
|
||||
|
||||
def _makeOAuthRequest(self, url, token=None, params=None, http_method="GET"):
|
||||
def _makeOAuthRequest(self, url, token=None, params=None):
|
||||
oauth_base_params = {
|
||||
'oauth_version': "1.0",
|
||||
'oauth_nonce': oauth.generate_nonce(),
|
||||
|
|
@ -91,14 +61,14 @@ class OAuthApi:
|
|||
|
||||
if not token:
|
||||
token = self._access_token
|
||||
request = oauth.Request(method=http_method,url=url,parameters=params)
|
||||
request = oauth.Request(method="GET", url=url, parameters=params)
|
||||
request.sign_request(self._signature_method, self._Consumer, token)
|
||||
return request
|
||||
|
||||
def ApiCall(self, call, type="GET", parameters={}):
|
||||
def ApiCall(self, call, parameters={}):
|
||||
return_value = []
|
||||
try:
|
||||
data = self._FetchUrl("https://api.twitter.com/1.1/" + call + ".json", type, parameters)
|
||||
data = self._FetchUrl("https://api.twitter.com/1.1/" + call + ".json", parameters)
|
||||
except urllib2.HTTPError, e:
|
||||
return e
|
||||
except urllib2.URLError, e:
|
||||
|
|
@ -106,17 +76,9 @@ class OAuthApi:
|
|||
else:
|
||||
return data
|
||||
|
||||
# now, begin our actual code.
|
||||
# APIDOCS https://dev.twitter.com/docs/api/1.1
|
||||
# TODO: centralize logging in. Add something to display error codes in the log while displaying error to irc.
|
||||
# TODO: work on colorizing tweets better.
|
||||
# TODO: maybe make an encode wrapper that can utilize strip_accents?
|
||||
# TODO: langs in search to validate against: https://dev.twitter.com/docs/api/1.1/get/help/languages
|
||||
|
||||
class Tweety(callbacks.Plugin):
|
||||
"""Simply use the commands available in this plugin. Allows fetching of the
|
||||
latest tween from a specified twitter handle, and listing of top ten
|
||||
trending tweets."""
|
||||
"""Public Twitter class for working with the API."""
|
||||
threaded = True
|
||||
|
||||
def __init__(self, irc):
|
||||
|
|
@ -127,6 +89,7 @@ class Tweety(callbacks.Plugin):
|
|||
self._checkAuthorization()
|
||||
|
||||
def _checkAuthorization(self):
|
||||
""" Check if we have our keys and can auth."""
|
||||
if not self.twitterApi:
|
||||
failTest = False
|
||||
for checkKey in ('consumerKey', 'consumerSecret', 'accessKey', 'accessSecret'):
|
||||
|
|
@ -181,23 +144,18 @@ class Tweety(callbacks.Plugin):
|
|||
return re.sub("&#?\w+;", fixup, text)
|
||||
|
||||
def _time_created_at(self, s):
|
||||
"""
|
||||
Takes a datetime string object that comes from twitter and twitter search timelines and returns a relative date.
|
||||
"""
|
||||
# twitter search and timelines use different timeformats
|
||||
# timeline's created_at Tue May 08 10:58:49 +0000 2012
|
||||
# search's created_at Thu, 06 Oct 2011 19:41:12 +0000
|
||||
try:
|
||||
"""Return relative delta."""
|
||||
|
||||
try: # timeline's created_at Tue May 08 10:58:49 +0000 2012
|
||||
ddate = time.strptime(s, "%a %b %d %H:%M:%S +0000 %Y")[:-2]
|
||||
except ValueError:
|
||||
try:
|
||||
try: # search's created_at Thu, 06 Oct 2011 19:41:12 +0000
|
||||
ddate = time.strptime(s, "%a, %d %b %Y %H:%M:%S +0000")[:-2]
|
||||
except ValueError:
|
||||
return "unknown"
|
||||
|
||||
# do the math
|
||||
created_at = datetime(*ddate, tzinfo=None)
|
||||
d = datetime.utcnow() - created_at
|
||||
d = datetime.utcnow() - datetime(*ddate, tzinfo=None)
|
||||
|
||||
# now parse and return.
|
||||
if d.days:
|
||||
|
|
@ -210,7 +168,6 @@ class Tweety(callbacks.Plugin):
|
|||
rel_time = "%ss ago" % (d.seconds)
|
||||
return rel_time
|
||||
|
||||
|
||||
def _outputTweet(self, irc, msg, nick, name, text, time, tweetid):
|
||||
"""
|
||||
Takes a group of strings and outputs a Tweet to IRC. Used for tsearch and twitter.
|
||||
|
|
@ -239,7 +196,6 @@ class Tweety(callbacks.Plugin):
|
|||
|
||||
irc.reply(ret)
|
||||
|
||||
|
||||
def _createShortUrl(self, nick, tweetid):
|
||||
"""
|
||||
Takes a nick and tweetid and returns a shortened URL via is.gd service.
|
||||
|
|
@ -254,7 +210,6 @@ class Tweety(callbacks.Plugin):
|
|||
except:
|
||||
return False
|
||||
|
||||
|
||||
def _woeid_lookup(self, lookup):
|
||||
"""
|
||||
Use Yahoo's API to look-up a WOEID.
|
||||
|
|
@ -285,7 +240,7 @@ class Tweety(callbacks.Plugin):
|
|||
##########################
|
||||
|
||||
def woeidlookup(self, irc, msg, args, lookup):
|
||||
"""[location]
|
||||
"""<location>
|
||||
Search Yahoo's WOEID DB for a location. Useful for the trends variable.
|
||||
"""
|
||||
|
||||
|
|
@ -299,27 +254,20 @@ class Tweety(callbacks.Plugin):
|
|||
|
||||
|
||||
# RATELIMITING
|
||||
# https://dev.twitter.com/docs/api/1.1/get/application/rate_limit_status
|
||||
# https://dev.twitter.com/docs/rate-limiting/1.1
|
||||
# https://dev.twitter.com/docs/rate-limiting/1.1/limits
|
||||
#< X-Rate-Limit-Limit: 15
|
||||
#< X-Rate-Limit-Remaining: 13
|
||||
#< X-Rate-Limit-Reset: 1357963140 / time.now()
|
||||
|
||||
def ratelimits(self, irc, msg, args):
|
||||
"""
|
||||
Display current rate limits for your twitter API account.
|
||||
"""
|
||||
|
||||
data = self.twitterApi.ApiCall('application/rate_limit_status') #, parameters={'resources':optstatus})
|
||||
|
||||
try:
|
||||
data = json.loads(data)
|
||||
except:
|
||||
irc.reply("Failed to lookup rate limit data. Something might have gone wrong. Data: %s" % data)
|
||||
irc.reply("Failed to lookup ratelimit data: %s" % data)
|
||||
return
|
||||
|
||||
data = data.get('resources', None)
|
||||
|
||||
if not data: # simple check if we have part of the json dict.
|
||||
irc.reply("Failed to fetch application rate limit status. Something could be wrong with Twitter.")
|
||||
self.log.error(data)
|
||||
|
|
@ -337,8 +285,6 @@ class Tweety(callbacks.Plugin):
|
|||
|
||||
ratelimits = wrap(ratelimits)
|
||||
|
||||
|
||||
|
||||
def trends(self, irc, msg, args, getopts, optwoeid):
|
||||
"""[--exclude] <location>
|
||||
|
||||
|
|
@ -372,8 +318,8 @@ class Tweety(callbacks.Plugin):
|
|||
irc.reply("ERROR: Cannot load trends: {0}".format(data)) # error also throws 404.
|
||||
return
|
||||
|
||||
# package together in object and output.
|
||||
ttrends = string.join([trend['name'].encode('utf-8') for trend in data[0]['trends']], " | ")
|
||||
|
||||
irc.reply("Top 10 Twitter Trends in {0} :: {1}".format(ircutils.bold(location), ttrends))
|
||||
|
||||
trends = wrap(trends, [getopts({'exclude':''}), optional('text')])
|
||||
|
|
@ -425,7 +371,6 @@ class Tweety(callbacks.Plugin):
|
|||
|
||||
tsearch = wrap(tsearch, [getopts({'num':('int'), 'searchtype':('literal', ('popular', 'mixed', 'recent')), 'lang':('somethingWithoutSpaces')}), ('text')])
|
||||
|
||||
|
||||
def twitter(self, irc, msg, args, optlist, optnick):
|
||||
"""[--noreply] [--nort] [--num number] <nick> | <--id id> | [--info nick]
|
||||
|
||||
|
|
|
|||
29
test.py
29
test.py
|
|
@ -1,32 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
###
|
||||
# Copyright (c) 2011-2013, Terje Hoås, spline
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions, and the following disclaimer.
|
||||
# * 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.
|
||||
# * Neither the name of the author of this software nor the name of
|
||||
# contributors to this software may be used to endorse or promote products
|
||||
# derived from this software without specific prior written consent.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Copyright (c) 2013, spline
|
||||
###
|
||||
|
||||
from supybot.test import *
|
||||
|
|
|
|||
Loading…
Reference in New Issue