From 45b3405c870b0395cc8d7fa48f4fcf1e3aeb312b Mon Sep 17 00:00:00 2001 From: Lucy Joshua Date: Sun, 29 Jan 2023 01:20:13 +0200 Subject: [PATCH 1/4] New complete refactor --- BotYamPoster.py | 72 ++++++++++++++++++++++++++++++ main.py | 114 +++++++++-------------------------------------- requirements.txt | 5 ++- 3 files changed, 98 insertions(+), 93 deletions(-) create mode 100644 BotYamPoster.py diff --git a/BotYamPoster.py b/BotYamPoster.py new file mode 100644 index 0000000..d9af346 --- /dev/null +++ b/BotYamPoster.py @@ -0,0 +1,72 @@ +import tweepy +import os +import syslog +import random +import json +from main import Connector +from main import init_api + +def init_streamobject(): + syslog.syslog(syslog.LOG_INFO, "Loading Stream object...") + bearer = os.getenv("BEARER") + return BotYamPoster(bearer) + +def post_reply(conn, victim_bank, tweet, words, reply_text, postcounter): + # Search for word in word bank + if any(word in tweet.data['text'] for word in words): + # Post reply + if tweet.data['author_id'] in victim_bank.author_id: + reply_text = victim_bank.text[random.randint(0,2)] + "\n" + reply_text + res = conn.api.create_tweet( + text=reply_text, + in_reply_to_tweet_id=tweet["id"] + ) + response_data = f"RESPONDING: {res.data['text']}" + syslog.syslog(syslog.LOG_INFO, response_data) + return (postcounter + 1) + +class BotYamPoster(tweepy.StreamingClient): + + # Define a callback function to handle tweets + def on_tweet(self, tweet): + # Make it easy on Yashar + + postcounter = 0 + + if (not "@FromBotYam" in tweet.data['text'] and random.randint(0,3) != 0): + return + + # Don't use bot for own replies + if tweet.data['author_id'] == "1604848395805401092": + return + + conn = Connector() + i, d = conn.conn_consul.get.kv('botyam/reply_bank') + reply_bank = json.loads(d["Value"]) + + # Debug + tweet_data = f"NEW TWEET from @{conn.api.get_user(id=tweet.data['author_id']).data['username']}: {tweet.data['text']}" + syslog.syslog(syslog.LOG_INFO, tweet_data) + + # Spare me if starts with RT + if tweet.data['text'][:2] == "RT": + syslog.syslog(syslog.LOG_INFO, "Skipping retweet...") + return + + # Run on all gags + for gag in reply_bank.gags: + post_reply(conn, reply_bank.victims, tweet, gag.keywords, gag.reply, postcounter) + + # Special gags + if reply_bank.special_gags['haikar_misadot'].keywords[0] in tweet.data["text"]: + post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['haikar_misadot'].keywords, reply_bank.special_gags['haikar_misadot'].reply) + elif not any(gebol in tweet.data['text'] for gebol in reply_bank.gags[1].keywords) and any(misada in tweet.data['text'] for misada in reply_bank.special_gags['misadot'].keywords): + post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['misadot'].keywords) + + if any(tilter in tweet.data['text'] for tilter in reply_bank.special_gags['tilt'].keywords) or (postcounter == 0 and not "@FromBotYam" in tweet.data['text']): + post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['tilt'].keywords, reply_bank.special_gags['tilt'].reply) + + # Define a callback function to handle errors + def on_error(self, status_code): + # Print the error code + syslog.syslog(syslog.LOG_ERR, status_code) diff --git a/main.py b/main.py index c60949c..fadefdb 100644 --- a/main.py +++ b/main.py @@ -1,104 +1,34 @@ import tweepy import os import syslog -import random +import consul +import json +from BotYamPoster import BotYamPoster +from BotYamPoster import init_streamobject -def init_api(): - # Syslog report - syslog.syslog(syslog.LOG_INFO, "Loading API...") - # Secrets - consumer_key = os.getenv("CONSUMER_KEY") - consumer_secret = os.getenv("CONSUMER_SECRET") - access_token = os.getenv("ACCESS_TOKEN") - access_token_secret = os.getenv("ACCESS_TOKEN_SECRET") - bearer = os.getenv("BEARER") +class Connector: + conn_consul = set() + api = set() - return tweepy.Client( - bearer_token=bearer, - consumer_key=consumer_key, - consumer_secret=consumer_secret, - access_token=access_token, - access_token_secret=access_token_secret) + def __init__(self): + syslog.syslog(syslog.LOG_INFO, "Loading Consul connector...") + # TODO: Add token + conn_consul = consul.Consul(host='', port='') -def init_streamobject(): - syslog.syslog(syslog.LOG_INFO, "Loading Stream object...") - bearer = os.getenv("BEARER") - return BotYamPoster(bearer) + api = Connector.init_api(conn_consul) -def post_reply(api, tweet, words, reply_text): - # Search for word in word bank - if any(word in tweet.data['text'] for word in words): - # Post reply - res = api.create_tweet( - text=reply_text, - in_reply_to_tweet_id=tweet["id"] - ) - response_data = f"RESPONDING: {res.data['text']}" - syslog.syslog(syslog.LOG_INFO, response_data) + def init_api(conn_consul): + # Syslog report + syslog.syslog(syslog.LOG_INFO, "Loading Twitter API connector...") + i, kv_keys = conn_consul.kv.get('botyam/api') -# Poster class -class BotYamPoster(tweepy.StreamingClient): - - # Define a callback function to handle tweets - def on_tweet(self, tweet): - # Make it easy on Yashar - if (tweet.data['author_id'] == "1533213104" and random.randint(0,3) != 0): - return - - # Don't use bot for own replies - if tweet.data['author_id'] == "1604848395805401092": - return - - api = init_api() - # Debug - tweet_data = f"NEW TWEET from @{api.get_user(id=tweet.data['author_id']).data['username']}: {tweet.data['text']}" - syslog.syslog(syslog.LOG_INFO, tweet_data) - - # Spare me if starts with RT - if tweet.data['text'][:2] == "RT": - syslog.syslog(syslog.LOG_INFO, "Skipping retweet...") - return - - # Words bank - bat_yam_words = ['בת ים', 'בת ימ', 'בת-ים', 'בת-ימ', 'https://t.co/PZqQaUVGAM'] - gebels_words = ['גבלס', 'נאצי', 'היטלר', 'קורונה', 'מסמכים', 'ההסמכה'] - police_words = ['שוטר', 'מלשין', 'מלשינ', 'נלשן', 'מלשנ', 'להלשין', 'משטרה', 'משטרות', 'סירנה', 'שיטור', 'בוגדים', 'בוגד', 'בגידה', '👮‍♀️', '🚨', '🚔', '🚓', '👮‍♂️', 'קטטה', 'מתקוטט', 'משטרע', 'מאפיה', 'טרור', 'סירנות', '1312', '13.12', '1 3 1 2', '13 12', '1 312', '131 2', '13-12', '1-312', '131-2', '1-3-1-2', '1 3 12', '1 3 12', '13 1 2', '1-3-12', '1-3-12', '13-1-2', 'acab', 'ac ab', 'ACAB', 'AC AB', 'אגאב', 'קצין', 'קצינ', 'קצונה', 'צהוב', 'כחול'] - misadot_words = ['העיקר מסעדות', 'מסעדה', 'מסעדות'] - smol_words = ['שמאל', '0מול', 'סמול'] - reply_words = ['@FromBotYam'] - - # Reply bank - reply_text_batyam = "https://twitter.com/FromBotYam/status/1611546128524185601/video/1" - reply_text_police = "https://twitter.com/FromBotYam/status/1611542331781529601/video/1" - reply_text_gebels = "https://twitter.com/FromBotYam/status/1611548817853227009/video/1" - reply_text_misadot = [reply_text_gebels, "https://twitter.com/FromBotYam/status/1612853363066175490/video/1", "https://twitter.com/FromBotYam/status/1616828733314170881/video/1"] - reply_text_smol = "https://twitter.com/FromBotYam/status/1613249771275182089/video/1" - reply_videons_reply = ["https://twitter.com/FromBotYam/status/1611495568148238336/video/1", "https://twitter.com/FromBotYam/status/1612852295980683264/video/1"] - reply_text_reply = f"מה עכשיו לערב אותי פה חבורה של קקות {reply_videons_reply[random.randint(0,1)]}" - - # Users bank - batyam_folks = ['134339937', '1533213104'] - - # Replies - post_reply(api, tweet, reply_words, reply_text_reply) - post_reply(api, tweet, gebels_words, reply_text_gebels) - post_reply(api, tweet, police_words, reply_text_police) - if any(botyam_og in tweet.data['author_id'] for botyam_og in batyam_folks): - post_reply(api, tweet, bat_yam_words, reply_text_batyam) - # Misadot (will be sectioned off later) - if tweet.data['text'] == misadot_words[0]: - post_reply(api, tweet, misadot_words[0], reply_text_misadot[-1]) - if not any(gebels_word in tweet.data['text'] for gebels_word in gebels_words): - post_reply(api, tweet, misadot_words, reply_text_misadot[random.randint(0,2)]) - else: - post_reply(api, tweet, misadot_words, reply_text_misadot[random.randint(1,2)]) - post_reply(api, tweet, smol_words, reply_text_smol) - - # Define a callback function to handle errors - def on_error(self, status_code): - # Print the error code - syslog.syslog(syslog.LOG_ERR, status_code) + return tweepy.Client( + bearer_token=json.loads(kv_keys['Value']).bearer, + consumer_key=json.loads(kv_keys['Value']).consumer_key, + consumer_secret=json.loads(kv_keys['Value']).consumer_secret, + access_token=json.loads(kv_keys['Value']).access_token, + access_token_secret=json.loads(kv_keys['Value']).access_token_secret) def main(): syslog.syslog(syslog.LOG_INFO, "BOT-YAM - VERSION 2.1.2 >>>>") diff --git a/requirements.txt b/requirements.txt index 3907e3b..0c1046f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,7 @@ PyYAML==5.3.1 requests==2.28.1 requests-oauthlib==1.3.1 tweepy==4.12.1 -urllib3==1.26.13 \ No newline at end of file +urllib3==1.26.13 +jsonschema==3.2.0 +six==1.16.0 +python-consul==1.1.0 \ No newline at end of file From 1e8761d7b04318b85e2c67920d3fb1fc0b5f2249 Mon Sep 17 00:00:00 2001 From: Lucy Joshua <43093984+notBscalE@users.noreply.github.com> Date: Sun, 29 Jan 2023 20:51:35 +0200 Subject: [PATCH 2/4] Changing structure --- BotYamPoster.py => src/BotYamPoster.py | 0 main.py => src/main.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename BotYamPoster.py => src/BotYamPoster.py (100%) rename main.py => src/main.py (100%) diff --git a/BotYamPoster.py b/src/BotYamPoster.py similarity index 100% rename from BotYamPoster.py rename to src/BotYamPoster.py diff --git a/main.py b/src/main.py similarity index 100% rename from main.py rename to src/main.py From a8232064f61f1fb32eadc63f2e162a38c74c465b Mon Sep 17 00:00:00 2001 From: Lucy Joshua <43093984+notBscalE@users.noreply.github.com> Date: Sun, 29 Jan 2023 20:51:57 +0200 Subject: [PATCH 3/4] Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index e5af681..3994cd9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,4 +2,4 @@ FROM python:latest COPY . /etc/botyam WORKDIR /etc/botyam RUN pip install -r requirements.txt -CMD ["python3", "./main.py"] \ No newline at end of file +CMD ["python3", "./src/main.py"] \ No newline at end of file From 3f2320a6fcb43b82ebbce43a1a837e3cf1c34696 Mon Sep 17 00:00:00 2001 From: Lucy Joshua Date: Mon, 30 Jan 2023 23:22:21 +0200 Subject: [PATCH 4/4] Switch to Redis --- requirements.txt | 3 ++- src/BotYamPoster.py | 39 +++++++++++++++++++++++++++------------ src/main.py | 43 +++++++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 29 deletions(-) diff --git a/requirements.txt b/requirements.txt index 0c1046f..38d05a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ tweepy==4.12.1 urllib3==1.26.13 jsonschema==3.2.0 six==1.16.0 -python-consul==1.1.0 \ No newline at end of file +crc16=0.1.1 +python-redis=0.3.0 \ No newline at end of file diff --git a/src/BotYamPoster.py b/src/BotYamPoster.py index d9af346..7e1b1f4 100644 --- a/src/BotYamPoster.py +++ b/src/BotYamPoster.py @@ -4,16 +4,15 @@ import syslog import random import json from main import Connector -from main import init_api -def init_streamobject(): +def init_streamobject(conn): syslog.syslog(syslog.LOG_INFO, "Loading Stream object...") - bearer = os.getenv("BEARER") - return BotYamPoster(bearer) + return BotYamPoster(conn.get_bearer()) -def post_reply(conn, victim_bank, tweet, words, reply_text, postcounter): +def post_reply(conn, victim_bank, tweet, words, reply_text_bank, postcounter): # Search for word in word bank if any(word in tweet.data['text'] for word in words): + reply_text = reply_text_bank[random.randint(0, (reply_text_bank.len()-1))] # Post reply if tweet.data['author_id'] in victim_bank.author_id: reply_text = victim_bank.text[random.randint(0,2)] + "\n" + reply_text @@ -41,8 +40,7 @@ class BotYamPoster(tweepy.StreamingClient): return conn = Connector() - i, d = conn.conn_consul.get.kv('botyam/reply_bank') - reply_bank = json.loads(d["Value"]) + reply_bank = json.loads(conn.dbconn.get_reply_bank()) # Debug tweet_data = f"NEW TWEET from @{conn.api.get_user(id=tweet.data['author_id']).data['username']}: {tweet.data['text']}" @@ -55,16 +53,33 @@ class BotYamPoster(tweepy.StreamingClient): # Run on all gags for gag in reply_bank.gags: - post_reply(conn, reply_bank.victims, tweet, gag.keywords, gag.reply, postcounter) + postcounter = post_reply(conn, reply_bank.victims, tweet, gag.keywords, gag.reply, postcounter) # Special gags if reply_bank.special_gags['haikar_misadot'].keywords[0] in tweet.data["text"]: - post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['haikar_misadot'].keywords, reply_bank.special_gags['haikar_misadot'].reply) + postcounter = post_reply( + conn, + reply_bank.victims, + tweet, + reply_bank.special_gags['haikar_misadot'].keywords, + reply_bank.special_gags['haikar_misadot'].reply, + postcounter) elif not any(gebol in tweet.data['text'] for gebol in reply_bank.gags[1].keywords) and any(misada in tweet.data['text'] for misada in reply_bank.special_gags['misadot'].keywords): - post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['misadot'].keywords) + postcounter = post_reply( + conn, + reply_bank.victims, + tweet, + reply_bank.special_gags['misadot'].keywords, + reply_bank.special_gags['misadot'].reply, + postcounter) - if any(tilter in tweet.data['text'] for tilter in reply_bank.special_gags['tilt'].keywords) or (postcounter == 0 and not "@FromBotYam" in tweet.data['text']): - post_reply(conn, reply_bank.victims, tweet, reply_bank.special_gags['tilt'].keywords, reply_bank.special_gags['tilt'].reply) + if any(tilter in tweet.data['text'] for tilter in reply_bank.special_gags['tilt'].keywords) or (postcounter == 0 and "@FromBotYam" in tweet.data['text']): + postcounter = post_reply( + conn, + reply_bank.victims, + tweet, reply_bank.special_gags['tilt'].keywords, + reply_bank.special_gags['tilt'].reply, + postcounter) # Define a callback function to handle errors def on_error(self, status_code): diff --git a/src/main.py b/src/main.py index fadefdb..02c7402 100644 --- a/src/main.py +++ b/src/main.py @@ -1,40 +1,51 @@ import tweepy import os import syslog -import consul import json +import redis from BotYamPoster import BotYamPoster from BotYamPoster import init_streamobject -class Connector: - conn_consul = set() - api = set() - +class Connector(): def __init__(self): syslog.syslog(syslog.LOG_INFO, "Loading Consul connector...") # TODO: Add token - conn_consul = consul.Consul(host='', port='') + self.dbconn = redis.Redis( + host=os.getenv("REDIS_HOST"), + port=os.getenv("REDIS_PORT"), + password=os.getenv("REDIS_CREDENTIALS") + ) - api = Connector.init_api(conn_consul) + self.api = Connector.init_api(self.dbconn) - def init_api(conn_consul): + def init_api(dbconn): # Syslog report syslog.syslog(syslog.LOG_INFO, "Loading Twitter API connector...") - i, kv_keys = conn_consul.kv.get('botyam/api') return tweepy.Client( - bearer_token=json.loads(kv_keys['Value']).bearer, - consumer_key=json.loads(kv_keys['Value']).consumer_key, - consumer_secret=json.loads(kv_keys['Value']).consumer_secret, - access_token=json.loads(kv_keys['Value']).access_token, - access_token_secret=json.loads(kv_keys['Value']).access_token_secret) + bearer_token=str(dbconn.hget("api", "bearer")), + consumer_key=str(dbconn.hget("api", "consumer_key")), + consumer_secret=str(dbconn.hget("api", "consumer_secret")) + access_token=str(dbconn.hget("api", "access_token")), + access_token_secret=str(dbconn.hget("api","access_token_secret")) + ) + + def get_reply_bank(self): + return json.loads(self.dbconn.get('reply_bank')) + + def get_victims(self): + return json.loads(self.dbconn.get('reply_bank')).victims + + def get_bearer(self): + return str(self.dbconn.hget("api", "bearer")) def main(): syslog.syslog(syslog.LOG_INFO, "BOT-YAM - VERSION 2.1.2 >>>>") - stream = init_streamobject() + conn = Connector() + stream = init_streamobject(conn) syslog.syslog(syslog.LOG_INFO, "Adding stream rules...") - stream.add_rules(tweepy.StreamRule("from:LucyBscalE OR from:aviv_yashar OR from:shaulig OR from:DvirAviam OR from:YoavFried1 OR from:StevenRaz5 OR from:nir_hau")) + stream.add_rules(tweepy.StreamRule(conn.get_victims().stream_filter)) stream.add_rules(tweepy.StreamRule("@FromBotYam")) # Start listening for tweets syslog.syslog(syslog.LOG_INFO, "Starting Twitter stream!")