reworked twitterbot according to new scheme

This commit is contained in:
b3yond 2018-03-28 23:33:04 +02:00
parent 49bd00fba3
commit 66bb1f86a3
3 changed files with 53 additions and 160 deletions

View file

@ -1,190 +1,71 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from config import config
import logging import logging
import tweepy import tweepy
import re import re
import requests import requests
from time import sleep
import report import report
from user import User from bot import Bot
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class TwitterBot(object): class TwitterBot(Bot):
""" def get_api(self, user):
This bot retweets all tweets which keys = user.get_api_keys()
1) mention him,
2) contain at least one of the triggerwords provided.
api: The api object, generated with your oAuth keys, responsible for
communication with twitter rest API
last_mention: the ID of the last tweet which mentioned you
"""
def __init__(self, uid):
"""
Initializes the bot and loads all the necessary data.
Tweet
"""
self.user = User(uid)
# initialize API access
keys = self.get_api_keys()
auth = tweepy.OAuthHandler(consumer_key=keys[0], auth = tweepy.OAuthHandler(consumer_key=keys[0],
consumer_secret=keys[1]) consumer_secret=keys[1])
auth.set_access_token(keys[2], # access_token_key auth.set_access_token(keys[2], # access_token_key
keys[3]) # access_token_secret keys[3]) # access_token_secret
self.api = tweepy.API(auth) return tweepy.API(auth)
self.last_mention = self.user.get_seen_tweet() def crawl(self, user):
self.waitcounter = 0
def get_api_keys(self):
"""
How to get these keys is described in doc/twitter_api.md
After you received keys, store them in your config.toml like this:
[tapp]
consumer_key = "..."
consumer_secret = "..."
[tuser]
access_token_key = "..."
access_token_secret = "..."
:return: keys: list of these 4 strings.
"""
keys = [config['twitter']['consumer_key'],
config['twitter']['consumer_secret']]
row = self.user.get_twitter_token()
keys.append(row[0])
keys.append(row[1])
return keys
def save_last(self):
""" Saves the last retweeted tweet in last_mention. """
self.user.save_seen_tweet(self.last_mention)
def waiting(self):
"""
If the counter is not 0, you should be waiting instead.
:return: self.waitcounter(int): if 0, do smth.
"""
if self.waitcounter > 0:
sleep(1)
self.waitcounter -= 1
return self.waitcounter
def crawl(self):
""" """
crawls all Tweets which mention the bot from the twitter rest API. crawls all Tweets which mention the bot from the twitter rest API.
:return: reports: (list of report.Report objects) :return: reports: (list of report.Report objects)
""" """
reports = [] reports = []
api = self.get_api(user)
last_mention = user.get_seen_tweet()
try: try:
if not self.waiting(): if last_mention == 0:
if self.last_mention == 0: mentions = api.mentions_timeline()
mentions = self.api.mentions_timeline() else:
else: mentions = api.mentions_timeline(
mentions = self.api.mentions_timeline( since_id=last_mention)
since_id=self.last_mention) for status in mentions:
for status in mentions: text = re.sub(
text = re.sub( "(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)", "", status.text)
"", status.text) reports.append(report.Report(status.author.screen_name,
reports.append(report.Report(status.author.screen_name, "twitter",
"twitter", text,
text, status.id,
status.id, status.created_at))
status.created_at)) user.save_seen_tweet(last_mention)
self.save_last() return reports
return reports
except tweepy.RateLimitError: except tweepy.RateLimitError:
logger.error("Twitter API Error: Rate Limit Exceeded", logger.error("Twitter API Error: Rate Limit Exceeded",
exc_info=True) exc_info=True)
self.waitcounter += 60*15 + 1 # :todo implement rate limiting
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
logger.error("Twitter API Error: Bad Connection", exc_info=True) logger.error("Twitter API Error: Bad Connection", exc_info=True)
self.waitcounter += 10
except tweepy.TweepError: except tweepy.TweepError:
logger.error("Twitter API Error: General Error", exc_info=True) logger.error("Twitter API Error: General Error", exc_info=True)
return [] return []
def repost(self, status): def post(self, user, report):
""" api = self.get_api(user)
Retweets a given tweet. try:
if report.source == self:
:param status: (report.Report object) api.retweet(report.id)
:return: toot: string of the tweet, to toot on mastodon. else:
""" # text = report.format()
while 1: if len(report.text) > 280:
try: text = report.text[:280 - 4] + u' ...'
self.api.retweet(status.id) except requests.exceptions.ConnectionError:
logger.info("Retweeted: " + status.format()) logger.error("Twitter API Error: Bad Connection",
if status.id > self.last_mention: exc_info=True)
self.last_mention = status.id # :todo implement rate limiting
self.save_last()
return status.format()
except requests.exceptions.ConnectionError:
logger.error("Twitter API Error: Bad Connection",
exc_info=True)
sleep(10)
# maybe one day we get rid of this error:
except tweepy.TweepError:
logger.error("Twitter Error", exc_info=True)
if status.id > self.last_mention:
self.last_mention = status.id
self.save_last()
return None
def post(self, status):
"""
Tweet a post.
:param status: (report.Report object)
"""
text = status.format()
if len(text) > 280:
text = status.text[:280 - 4] + u' ...'
while 1:
try:
self.api.update_status(status=text)
return
except requests.exceptions.ConnectionError:
logger.error("Twitter API Error: Bad Connection",
exc_info=True)
sleep(10)
def flow(self, trigger, to_tweet=()):
""" The flow of crawling mentions and retweeting them.
:param to_tweet: list of strings to tweet
:return list of retweeted tweets, to toot on mastodon
"""
# Tweet the reports from other sources
for post in to_tweet:
self.post(post)
# Store all mentions in a list of Status Objects
mentions = self.crawl()
# initialise list of strings for other bots
all_tweets = []
for status in mentions:
# Is the Text of the Tweet in the triggerlist?
if trigger.is_ok(status.text):
# Retweet status
toot = self.repost(status)
if toot:
all_tweets.append(toot)
# Return Retweets for posting on other bots
return all_tweets

View file

@ -10,9 +10,6 @@ import smtplib
from mastodon import Mastodon from mastodon import Mastodon
logger = logging.getLogger(__name__)
@get('/') @get('/')
@view('template/propaganda.tpl') @view('template/propaganda.tpl')
def propaganda(): def propaganda():
@ -153,6 +150,12 @@ def login_mastodon(user):
return dict(error='Login to Mastodon failed.') return dict(error='Login to Mastodon failed.')
logpath = config['logging']['logpath']
logger = logging.getLogger()
fh = logging.FileHandler(logpath)
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
application = bottle.default_app() application = bottle.default_app()
bottle.install(SessionPlugin('/')) bottle.install(SessionPlugin('/'))

View file

@ -1,3 +1,4 @@
from config import config
from bottle import response from bottle import response
from db import db from db import db
import jwt import jwt
@ -81,6 +82,14 @@ class User(object):
instance = db.cur.fetchone() instance = db.cur.fetchone()
return instance[1], instance[2], row[0], instance[0] return instance[1], instance[2], row[0], instance[0]
def get_twitter_credentials(self):
keys = [config['twitter']['consumer_key'],
config['twitter']['consumer_secret']]
row = self.get_twitter_token()
keys.append(row[0])
keys.append(row[1])
return keys
def get_seen_toot(self): def get_seen_toot(self):
db.execute("SELECT toot_id FROM seen_toots WHERE user_id = ?;", db.execute("SELECT toot_id FROM seen_toots WHERE user_id = ?;",
(self.uid, )) (self.uid, ))