2018-10-08 19:11:51 -06:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
import mastodon
|
2021-06-04 15:38:36 -06:00
|
|
|
import re, json, argparse
|
2019-01-11 05:47:42 -07:00
|
|
|
import functions
|
2018-10-08 19:11:51 -06:00
|
|
|
|
2019-08-06 21:46:57 -06:00
|
|
|
parser = argparse.ArgumentParser(description='Reply service. Leave running in the background.')
|
2021-06-04 15:38:36 -06:00
|
|
|
parser.add_argument(
|
|
|
|
'-c', '--cfg', dest='cfg', default='config.json', nargs='?',
|
2019-08-06 21:46:57 -06:00
|
|
|
help="Specify a custom location for config.json.")
|
|
|
|
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
cfg = json.load(open(args.cfg, 'r'))
|
2018-10-14 00:58:58 -06:00
|
|
|
|
2018-10-08 19:11:51 -06:00
|
|
|
client = mastodon.Mastodon(
|
2021-06-04 15:38:36 -06:00
|
|
|
client_id=cfg['client']['id'],
|
|
|
|
client_secret=cfg['client']['secret'],
|
|
|
|
access_token=cfg['secret'],
|
|
|
|
api_base_url=cfg['site'])
|
|
|
|
|
2018-10-08 19:11:51 -06:00
|
|
|
|
|
|
|
def extract_toot(toot):
|
2019-01-11 05:56:35 -07:00
|
|
|
text = functions.extract_toot(toot)
|
2021-06-04 15:38:36 -06:00
|
|
|
text = re.sub(r"^@[^@]+@[^ ]+\s*", r"", text) # remove the initial mention
|
|
|
|
text = text.lower() # treat text as lowercase for easier keyword matching (if this bot uses it)
|
2018-10-08 19:11:51 -06:00
|
|
|
return text
|
|
|
|
|
2021-06-04 15:38:36 -06:00
|
|
|
|
2018-10-08 19:11:51 -06:00
|
|
|
class ReplyListener(mastodon.StreamListener):
|
2021-06-04 15:38:36 -06:00
|
|
|
def on_notification(self, notification): # listen for notifications
|
|
|
|
if notification['type'] == 'mention': # if we're mentioned:
|
|
|
|
acct = "@" + notification['account']['acct'] # get the account's @
|
2018-10-08 19:11:51 -06:00
|
|
|
post_id = notification['status']['id']
|
2019-05-19 07:06:31 -06:00
|
|
|
|
2019-05-04 00:44:57 -06:00
|
|
|
# check if we've already been participating in this thread
|
|
|
|
try:
|
|
|
|
context = client.status_context(post_id)
|
|
|
|
except:
|
|
|
|
print("failed to fetch thread context")
|
|
|
|
return
|
|
|
|
me = client.account_verify_credentials()['id']
|
|
|
|
posts = 0
|
|
|
|
for post in context['ancestors']:
|
|
|
|
if post['account']['id'] == me:
|
2021-06-04 15:38:36 -06:00
|
|
|
pin = post["id"] # Only used if pin is called, but easier to call here
|
2019-05-04 00:44:57 -06:00
|
|
|
posts += 1
|
2019-05-19 07:06:31 -06:00
|
|
|
if posts >= cfg['max_thread_length']:
|
|
|
|
# stop replying
|
|
|
|
print("didn't reply (max_thread_length exceeded)")
|
|
|
|
return
|
2019-05-04 00:44:57 -06:00
|
|
|
|
2018-10-08 19:11:51 -06:00
|
|
|
mention = extract_toot(notification['status']['content'])
|
2021-06-04 15:38:36 -06:00
|
|
|
if (mention == "pin") or (mention == "unpin"): # check for keywords
|
2019-05-19 06:31:42 -06:00
|
|
|
print("Found pin/unpin")
|
2021-06-04 15:38:36 -06:00
|
|
|
# get a list of people the bot is following
|
2019-05-19 06:31:42 -06:00
|
|
|
validusers = client.account_following(me)
|
|
|
|
for user in validusers:
|
2021-06-04 15:38:36 -06:00
|
|
|
if user["id"] == notification["account"]["id"]: # user is #valid
|
2019-05-19 06:31:42 -06:00
|
|
|
print("User is valid")
|
2019-05-19 06:54:59 -06:00
|
|
|
visibility = notification['status']['visibility']
|
|
|
|
if visibility == "public":
|
|
|
|
visibility = "unlisted"
|
2019-05-19 06:31:42 -06:00
|
|
|
if mention == "pin":
|
|
|
|
print("pin received, pinning")
|
|
|
|
client.status_pin(pin)
|
2021-06-04 15:38:36 -06:00
|
|
|
client.status_post("Toot pinned!", post_id, visibility=visibility, spoiler_text=cfg['cw'])
|
2019-05-19 06:31:42 -06:00
|
|
|
else:
|
|
|
|
print("unpin received, unpinning")
|
2021-06-04 15:38:36 -06:00
|
|
|
client.status_post("Toot unpinned!", post_id, visibility=visibility, spoiler_text=cfg['cw'])
|
2019-05-19 06:31:42 -06:00
|
|
|
client.status_unpin(pin)
|
|
|
|
else:
|
|
|
|
print("User is not valid")
|
|
|
|
else:
|
2021-06-04 15:38:36 -06:00
|
|
|
toot = functions.make_toot(cfg) # generate a toot
|
|
|
|
toot = acct + " " + toot # prepend the @
|
|
|
|
print(acct + " says " + mention) # logging
|
2019-05-19 06:31:42 -06:00
|
|
|
visibility = notification['status']['visibility']
|
|
|
|
if visibility == "public":
|
|
|
|
visibility = "unlisted"
|
2021-06-04 15:38:36 -06:00
|
|
|
client.status_post(toot, post_id, visibility=visibility, spoiler_text=cfg['cw']) # send toost
|
|
|
|
print("replied with " + toot) # logging
|
|
|
|
|
2018-10-08 19:11:51 -06:00
|
|
|
|
|
|
|
rl = ReplyListener()
|
2021-06-04 15:38:36 -06:00
|
|
|
client.stream_user(rl) # go!
|