|
@@ -8,7 +8,7 @@ import sys
|
|
|
import time
|
|
|
|
|
|
class Bot(object):
|
|
|
- def __init__(self, access_token, since_at, instance_url, msg_template='', debug_mode=True, account_id=1, max_chars=500):
|
|
|
+ def __init__(self, access_token, instance_url, msg_template='', debug_mode=True, account_id=1, max_chars=500):
|
|
|
self.max_chars = max_chars
|
|
|
self.instance_url = instance_url
|
|
|
self.msg_template = Template(msg_template)
|
|
@@ -16,9 +16,14 @@ class Bot(object):
|
|
|
access_token=access_token,
|
|
|
api_base_url=self.instance_url
|
|
|
)
|
|
|
- self.since_at = since_at
|
|
|
self.debug_mode = debug_mode
|
|
|
|
|
|
+ #start by sending welcome to accounts that have registered after the bot has started
|
|
|
+ self.newest_account_creation_date = pytz.utc.localize(datetime.now())
|
|
|
+
|
|
|
+ #used to update self.newest_account_creation_date
|
|
|
+ self.newest_account_creation_date_record = self.newest_account_creation_date
|
|
|
+
|
|
|
self.log = logging.getLogger()
|
|
|
if self.debug_mode:
|
|
|
self.log.setLevel(logging.DEBUG)
|
|
@@ -30,33 +35,46 @@ class Bot(object):
|
|
|
|
|
|
self.account_id = account_id
|
|
|
|
|
|
- self.until = pytz.utc.localize(datetime.now() - timedelta(days=1))
|
|
|
- self.until = self.until.replace(hour=23, minute=59, second=59)
|
|
|
-
|
|
|
def _should_get_msg(self, account):
|
|
|
if self.debug_mode:
|
|
|
- print("Filtering {}".format(account.username))
|
|
|
- print("Created at: {}".format(account.created_at))
|
|
|
- print("self.since_at is {}".format(self.since_at))
|
|
|
- print("self.until is {}".format(self.until))
|
|
|
- return account.url.startswith(self.instance_url) and account.created_at >= self.since_at and account.created_at <= self.until and not account.locked
|
|
|
+ self.log.debug("--Filtering {}--".format(account.username))
|
|
|
+ self.log.debug("Account url: {}".format(account.url))
|
|
|
+ self.log.debug("Created at: {}".format(account.created_at))
|
|
|
+ self.log.debug("Newest account date {}".format(self.newest_account_creation_date))
|
|
|
+ self.log.debug("")
|
|
|
+
|
|
|
+ if account.created_at > self.newest_account_creation_date_record:
|
|
|
+ self.newest_account_creation_date_record = account.created_at
|
|
|
+
|
|
|
+ return account.url.startswith(self.instance_url) and account.created_at > self.newest_account_creation_date and not account.locked
|
|
|
|
|
|
def get_users(self):
|
|
|
users_to_msg = []
|
|
|
|
|
|
def get_prev(users):
|
|
|
- followers = self.client.fetch_previous(users)
|
|
|
+ followers = []
|
|
|
+ try:
|
|
|
+ followers = self.client.fetch_previous(users)
|
|
|
+ except:
|
|
|
+ self.log.error("Cannot fetch followers.")
|
|
|
|
|
|
filtered = [follower for follower in followers if self._should_get_msg(follower)]
|
|
|
users_to_msg.extend(filtered)
|
|
|
|
|
|
- # this assumes that followers are returned in descending order by follow date!
|
|
|
+ # this assumes that followers are returned in descending order by follow date
|
|
|
if len(filtered) == 0:
|
|
|
return users_to_msg
|
|
|
|
|
|
return get_prev(followers)
|
|
|
|
|
|
- followers = self.client.account_followers(self.account_id, limit=80)
|
|
|
+ followers = []
|
|
|
+ try:
|
|
|
+ followers = self.client.account_followers(self.account_id, limit=80)
|
|
|
+ except Exception as e:
|
|
|
+ self.log.error("Cannot fetch followers.")
|
|
|
+ self.log.exception(e)
|
|
|
+ except:
|
|
|
+ self.log.error("Error")
|
|
|
filtered = [follower for follower in followers if self._should_get_msg(follower)]
|
|
|
users_to_msg.extend(filtered)
|
|
|
|
|
@@ -65,53 +83,35 @@ class Bot(object):
|
|
|
|
|
|
return get_prev(followers)
|
|
|
|
|
|
- def _split_toot(toot, parts=[]):
|
|
|
- if len(toot) > self.max_chars:
|
|
|
- # find where to split
|
|
|
- index = self.max_chars
|
|
|
- while index > 0 and (toot[index] != ' ' or toot[index] != '\n'):
|
|
|
- index -= 1
|
|
|
- if index == 0:
|
|
|
- index = self.max_chars
|
|
|
-
|
|
|
- return _split_toot(toot[index+1:], parts=parts.append(toot[:index]))
|
|
|
-
|
|
|
- return parts.append(toot)
|
|
|
|
|
|
def send_msg(self, account):
|
|
|
msg = self.msg_template.render(account)
|
|
|
toots = msg.split('\n\n\n')
|
|
|
- self.log.debug(msg)
|
|
|
- if self.debug_mode:
|
|
|
- return
|
|
|
|
|
|
for toot in toots:
|
|
|
+ reply_id = None
|
|
|
+
|
|
|
if len(toot) < self.max_chars:
|
|
|
- self.client.status_post(toot, visibility='direct')
|
|
|
+ reply_id = self.client.status_post(toot, visibility='direct', in_reply_to_id=reply_id).id
|
|
|
+ if self.debug_mode:
|
|
|
+ self.log.debug("Replying to {}".format(reply_id))
|
|
|
else:
|
|
|
- reply_id = None
|
|
|
- for part in _split_toot(toot):
|
|
|
- reply_id = self.client.status_post(part,
|
|
|
- visibility='direct',
|
|
|
- in_reply_to_status_id=reply_id).id
|
|
|
+ self.log.error("Make sure to correctly split the toot into parts that can be sent individually")
|
|
|
|
|
|
def go(self):
|
|
|
users_to_msg = self.get_users()
|
|
|
- if self.debug_mode:
|
|
|
- self.log.debug('in debug mode so not actually sending toots, but if I was, I\'d be sending to ' \
|
|
|
- '{} accounts'.format(len(users_to_msg)))
|
|
|
- self.log.debug('here\'s the toots that I would be sending:')
|
|
|
+ self.newest_account_creation_date = self.newest_account_creation_date_record
|
|
|
|
|
|
for u in users_to_msg:
|
|
|
self.send_msg(u)
|
|
|
|
|
|
- self.log.info('{} toots sent!'. format(len(users_to_msg)))
|
|
|
+ if self.debug_mode:
|
|
|
+ self.log.debug('{} toots sent'.format(len(users_to_msg)))
|
|
|
|
|
|
def create_bot():
|
|
|
env = Env()
|
|
|
env.read_env()
|
|
|
access_token = env('ACCESS_TOKEN')
|
|
|
- days_since = env.int('DAYS_SINCE', 1)
|
|
|
max_chars = env.int('INSTANCE_MAX_CHARS', 500)
|
|
|
instance_base_url = env('INSTANCE_BASE_URL')
|
|
|
msg_template = ''
|
|
@@ -120,9 +120,7 @@ def create_bot():
|
|
|
debug_mode = env.bool('DEBUG', False)
|
|
|
account_id = env.int('ACCOUNT_ID')
|
|
|
|
|
|
- since = pytz.utc.localize(datetime.now() - timedelta(days=days_since))
|
|
|
bot = Bot(access_token,
|
|
|
- since_at=since,
|
|
|
instance_url=instance_base_url,
|
|
|
msg_template=msg_template,
|
|
|
debug_mode=debug_mode,
|
|
@@ -131,12 +129,30 @@ def create_bot():
|
|
|
|
|
|
return bot
|
|
|
|
|
|
+def debug_shell(bot):
|
|
|
+ cmd = input('debug command> ').strip()
|
|
|
+ if cmd == 'c' or cmd == 'continue':
|
|
|
+ return False
|
|
|
+ elif cmd == 'update date':
|
|
|
+ bot.newest_account_creation_date = pytz.utc.localize(datetime.now())
|
|
|
+ bot.newest_account_creation_date_record = bot.newest_account_creation_date
|
|
|
+ elif cmd.startswith('before'):
|
|
|
+ bot.newest_account_creation_date = pytz.utc.localize(datetime.now() - timedelta(hours=int(cmd.split(' ')[1])))
|
|
|
+ bot.newest_account_creation_date_record = bot.newest_account_creation_date
|
|
|
+ elif cmd == 'print date':
|
|
|
+ bot.log.debug(bot.newest_account_creation_date)
|
|
|
+ return True
|
|
|
+
|
|
|
def run():
|
|
|
bot = create_bot()
|
|
|
|
|
|
while True:
|
|
|
+ if bot.debug_mode:
|
|
|
+ while debug_shell(bot):
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ time.sleep(30) # 30 secs
|
|
|
bot.go()
|
|
|
- time.sleep(2*60) # 2 mins
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
run()
|