def plugin(srv, item): _DEFAULT_URL = 'https://mastodon.social' srv.logging.debug("*** MODULE=%s: service=%s, target=%s", __file__, item.service, item.target) if not HAVE_MASTODON: srv.logging.error("Python Mastodon.py is not installed") return False # item.config is brought in from the configuration file config = item.config clientcreds, usercreds, base_url = item.addrs text = item.message try: mastodon = Mastodon( client_id = clientcreds, access_token = usercreds, api_base_url = base_url ) mastodon.toot(text) except Exception, e: srv.logging.warning("Cannot post to Mastodon: %s" % (str(e))) return False
def register(self): import webbrowser self.check_params('handle') api_base_url = self.params['handle'].split('@')[-1] # get client data client_id = self.context.params.get(service_name, 'client_id') client_secret = self.context.params.get(service_name, 'client_secret') if (not client_id) or (not client_secret): client_id, client_secret = Mastodon.create_app( 'pywws', scopes=['write'], api_base_url=api_base_url) self.context.params.set(service_name, 'client_id', client_id) self.context.params.set(service_name, 'client_secret', client_secret) # create api api = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=api_base_url) # authorise auth_request_url = api.auth_request_url(scopes=['write']) if not webbrowser.open(auth_request_url, new=2, autoraise=0): print('Please use a web browser to open the following URL') print(auth_request_url) if sys.version_info[0] >= 3: input_ = input else: input_ = raw_input code = input_('Please enter the auth code shown in your web browser: ') code = code.strip() # log in access_token = api.log_in(code=code, scopes=['write']) self.context.params.set(service_name, 'access_token', access_token)
def auth(self, request): """ get the auth of the services :param request: contains the current session :type request: dict :rtype: dict """ # create app redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(), reverse('mastodon_callback')) us = UserService.objects.get(user=request.user, name='ServiceMastodon') client_id, client_secret = MastodonAPI.create_app( client_name="TriggerHappy", api_base_url=us.host, redirect_uris=redirect_uris) us.client_id = client_id us.client_secret = client_secret us.save() us = UserService.objects.get(user=request.user, name='ServiceMastodon') # get the token by logging in mastodon = MastodonAPI( client_id=client_id, client_secret=client_secret, api_base_url=us.host ) token = mastodon.log_in(username=us.username, password=us.password) us.token = token us.save() return self.callback_url(request)
def callback_url(self, request): us = UserService.objects.get(user=request.user, name='ServiceMastodon') mastodon = MastodonAPI( client_id=us.client_id, client_secret=us.client_secret, access_token=us.token, api_base_url=us.host ) redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(), reverse('mastodon_callback')) return mastodon.auth_request_url(redirect_uris=redirect_uris)
def save_data(self, trigger_id, **data): """ let's save the data :param trigger_id: trigger ID from which to save data :param data: the data to check to be used and save :type trigger_id: int :type data: dict :return: the status of the save statement :rtype: boolean """ title, content = super(ServiceMastodon, self).save_data(trigger_id, **data) # check if we have a 'good' title if self.title_or_content(title): content = str("{title} {link}").format(title=title, link=data.get('link')) content += get_tags(Mastodon, trigger_id) # if not then use the content else: content += " " + data.get('link') + " " + get_tags(Mastodon, trigger_id) content = self.set_mastodon_content(content) us = UserService.objects.get(user=self.user, token=self.token, name='ServiceMastodon') try: toot_api = MastodonAPI(client_id=us.client_id, client_secret=us.client_secret, access_token=self.token, api_base_url=us.host) except ValueError as e: logger.error(e) status = False update_result(trigger_id, msg=e, status=status) media_ids = None try: if settings.DJANGO_TH['sharing_media']: # do we have a media in the content ? content, media = self.media_in_content(content) if media: # upload the media first media_ids = toot_api.media_post(media_file=media) media_ids = [media_ids] toot_api.status_post(content, media_ids=media_ids) status = True except Exception as inst: logger.critical("Mastodon ERR {}".format(inst)) status = False update_result(trigger_id, msg=inst, status=status) return status
def get_service(hass, config, discovery_info=None): """Get the Mastodon notification service.""" from mastodon import Mastodon from mastodon.Mastodon import MastodonUnauthorizedError client_id = config.get(CONF_CLIENT_ID) client_secret = config.get(CONF_CLIENT_SECRET) access_token = config.get(CONF_ACCESS_TOKEN) base_url = config.get(CONF_BASE_URL) try: mastodon = Mastodon( client_id=client_id, client_secret=client_secret, access_token=access_token, api_base_url=base_url) mastodon.account_verify_credentials() except MastodonUnauthorizedError: _LOGGER.warning("Authentication failed") return None return MastodonNotificationService(mastodon)
def get_credential(**config): api_base_url = config.get('instance_url') if not api_base_url: raise Exception( 'Correctly specify instance_url on {}.'.format(CONFIG_FILE_NAME)) if not exists(CLIENT_SECRET_FILE_NAME): Mastodon.create_app( client_name=config.get('app_name') or 'chatbotdon', website=config.get('website') or 'https://github.com/kakakaya/chatbotdon', to_file=CLIENT_SECRET_FILE_NAME, api_base_url=api_base_url, ) access_token = None if exists(USER_SECRET_FILE_NAME): access_token = USER_SECRET_FILE_NAME m = Mastodon(client_id=CLIENT_SECRET_FILE_NAME, access_token=access_token, api_base_url=api_base_url) if not access_token: m.log_in( username=config.get('username'), password=config.get('password'), to_file=USER_SECRET_FILE_NAME, ) return m
def get_access_token(): config = ConfigParser() config.readfp(io.open('token.ini', 'r', encoding='utf_8_sig')) section = 'Token' api_base_url = config.get(section, 'api_base_url') username = config.get(section, 'username') password = config.get(section, 'password') client_id = config.get(section, 'client_id') access_token = config.get(section, 'access_token') scopes = ['read', 'write'] Mastodon.create_app( 'TOMOYODon', scopes=scopes, api_base_url=api_base_url, to_file=client_id ) mastodon = Mastodon( client_id=client_id, api_base_url=api_base_url ) mastodon.log_in( username=username, password=password, scopes=scopes, to_file=access_token )
def login(): response.headers['Access-Control-Allow-Origin'] = '*' response.content_type = "application/json" username = request.forms.get("username") # pylint: disable=no-member password = request.forms.get("password") # pylint: disable=no-member instance = request.forms.get("instance") # pylint: disable=no-member if debug: appname = "Nordcast (debug)" else: appname = "Nordcast" if not os.path.exists('clientcred.' + instance + '.secret'): Mastodon.create_app(appname, api_base_url='https://' + instance, to_file='clientcred.' + instance + '.secret') mastodon = Mastodon(client_id='clientcred.' + instance + '.secret', api_base_url='https://' + instance) mastodon.log_in( username, password, to_file='authtokens/' + username + '.' + instance + '.secret', ) if not os.path.exists("usercred.secret"): suid = str(uuid.uuid1()) if r.get("nordcast/uuids/" + username + "$$" + instance) == None: r.set("nordcast/uuids/" + username + "$$" + instance, suid) else: r.set( "nordcast/uuids/" + username + "$$" + instance, str(r.get("nordcast/uuids/" + username + "$$" + instance)).replace("b'", "").replace("'", "") + "," + suid) return json.dumps({"login": "******", "uuid": suid}) else: return "{\"login\": \"error\"}"
def initialize_mastodon(): server_url = config("MASTODON_SERVER") # make data dir mastodon_data_path = Path(__file__).parents[2] / "data" / "mastodon" # フォルダの方は Error を回避 try: Path(mastodon_data_path.parent).mkdir() Path(mastodon_data_path).mkdir() except FileExistsError: print("you have already make mastodon data folder") mastodon_client_data_path = mastodon_data_path / "my_clientcred.txt" mastodon_user_data_path = mastodon_data_path / "my_usercred.txt" # If you already have data file, Raise error for path in (mastodon_user_data_path, mastodon_client_data_path): if path.exists(): print(path.as_posix(), "is already exists") return False # get mastodon data Mastodon.create_app("client name", api_base_url=server_url, to_file=mastodon_client_data_path.as_posix()) mastodon = Mastodon(client_id=mastodon_client_data_path.as_posix(), api_base_url=server_url) mastodon.log_in(config("MASTODON_EMAIL"), config("MASTODON_PASS"), to_file=mastodon_user_data_path.as_posix()) return True
class HmsMastodon: """A class that provides features around the Mastodon wrapper.""" def __init__(self): """Default constructor.""" self.mastodon = Mastodon(settings.CLIENT_CREDS_FILE, access_token=settings.USER_CREDS_FILE, api_base_url=settings.API_BASE_URL) self.listener = None def init_streaming(self, rabbit): """Initialize the Mastodon streaming API.""" self.listener = TootStreamListener(rabbit) self.mastodon.user_stream(self.listener) def toot_new_status(self, data): """Toots the new status of the space.""" if data['is_open']: short_msg = strings.TWAUM_OPEN_SHORT long_msg = strings.TWAUM_OPEN else: short_msg = strings.TWAUM_CLOSED_SHORT long_msg = strings.TWAUM_CLOSED get_logger().info("Sending new status toot: {}".format(short_msg)) self.mastodon.status_post(long_msg, spoiler_text=short_msg) def toot(self, message): """Send a toot.""" get_logger().info("Sending toot: {}".format(message)) self.mastodon.status_post(message)
def main(config, data_dir, callback, exclude_user, timeline, limit, account_id): def online_callback( client=None, account=None, media_url=None, notif_type=None, orig_status=None, status=None, cache=None, ): """Take a toot from an online source, and archive it.""" if not status: return try: session = sessionmaker(get_engine(data_dir))() session.add(toot_from_status(status)) session.commit() print(' ... Saved archived message!') except Exception as e: print(str(e)) cfg = json.load(open(config)) try: client = Mastodon( access_token=cfg["mastodon_token"], api_base_url=cfg["mastodon_instance"], ) kwargs = { 'client': client, 'config': config, 'data_dir': data_dir, 'exclude_user': exclude_user, } if callback: # Callback for archived streamer was provided ArchiveSource(callback=callback, **kwargs).process() # TODO: Accept query params else: # Otherwise we're just a message sink streamer = ArchiveSink(callback=online_callback, **kwargs) streamer.process(timeline=timeline, limit=limit, account_id=account_id) except Exception as e: print(str(e)) time.sleep(10)
def kafka_toot(id, password, mastodon_url, kafka_url, kafka_topic): if id != None and password != None and mastodon_url != None and kafka_url != None and kafka_topic != None: consumer = KafkaConsumer(kafka_topic, bootstrap_servers=kafka_url) login(id, password, mastodon_url) mastodon = Mastodon(access_token='pytooter_usercred.secret', api_base_url=mastodon_url) for msg in consumer: print(msg.value) mastodon.toot(msg.value) if id == None: print('ERROR: ID env is not defined.') if password == None: print('ERROR: PASSWORD env is not defined.') if mastodon_url == None: print('ERROR: MASTODON_URL env is not defined.') if kafka_url == None: print('ERROR: KAFKA_URL env is not defined.') if kafka_topic == None: print('ERROR: KAFKA_TOPIC env is not defined.')
def init(config): API_BASE_URL = config['Mastodon']['API_BASE_URL'] if not os.path.exists('clientcred.secret'): Mastodon.create_app( config['Mastodon']['APP_NAME'], api_base_url = API_BASE_URL, to_file = 'clientcred.secret' ) mastodon = Mastodon( client_id = 'clientcred.secret', api_base_url = API_BASE_URL ) mastodon.log_in( config['Mastodon']['EMAIL'], config['Mastodon']['PASS_WORD'], to_file = 'usercred.secret' ) return mastodon
def get_mastodon(request): if not (request.session.has_key('instance') and (request.session.has_key('username') or request.session.has_key('access_token'))): raise NotLoggedInException() pool = MastodonPool() if request.session.has_key('access_token'): try: client = Client.objects.get( api_base_id=request.session['instance']) except (Client.DoesNotExist, Client.MultipleObjectsReturned): raise NotLoggedInException() if request.session['access_token'] in pool.keys(): mastodon = pool[request.session['access_token']] else: mastodon = Mastodon(client_id=client.client_id, client_secret=client.client_secret, api_base_url=client.api_base_id, access_token=request.session['access_token'], ratelimit_method='throw') pool[request.session['access_token']] = mastodon else: try: client = Client.objects.get( api_base_id=request.session['instance']) user = Account.objects.get(username=request.session['username']) except (Client.DoesNotExist, Client.MultipleObjectsReturned, Account.DoesNotExist, Account.MultipleObjectsReturned): raise NotLoggedInException() if user.access_token in pool.keys(): mastodon = pool[user.access_token] else: mastodon = Mastodon(client_id=client.client_id, client_secret=client.client_secret, access_token=user.access_token, api_base_url=client.api_base_id, ratelimit_method="throw") return mastodon
def create_application(url): print("Application not created, creating now...") if Mastodon.create_app("Mastopy", to_file="Mastopy_client-cred.secret", scopes=['read', 'write'], api_base_url=url): print("Application created!") else: print("Failed to create application!") sys.exit(1) pass
def get_mastodon(config_file): config = common.get_json(config_file) if config == None: print("File %s not found, exiting." % filename, file=sys.stderr) sys.exit(1) mastodon = Mastodon( client_id=config["client_id"], client_secret=config["client_secret"], access_token=config["access_token"], api_base_url='https://' + config["mastodon_hostname"] # E.g., mastodon.social ) return mastodon
def start_register(self, server): try: (id,secret)=Mastodon.create_app( client_name='mastaj xmpp gateway', api_base_url="https://"+server ) m=Mastodon( client_id=id, client_secret=secret, api_base_url="https://"+server ) url=m.auth_request_url( client_id=id, scopes=['read','write','follow'], redirect_uris='urn:ietf:wg:oauth:2.0:oob' ) self.mastodon=m self.mastodon_id=server print(url) return url except MastodonNetworkError: raise NetworkError()
def login(self, pace=False): """ Register app, authorize and return an instance of ``Mastodon`` """ url = self.url client_secret = self.client_secret user_secret = self.user_secret user_secret2 = self.user_secret2 if not os.path.isfile(client_secret): self.register() if not os.path.isfile(user_secret) and os.path.isfile(user_secret2): user_secret = user_secret2 if not os.path.isfile(user_secret): mastodon = self.authorize() else: if pace: # in case the user kept running into a General API problem mastodon = Mastodon(client_id=client_secret, access_token=user_secret, api_base_url=url, ratelimit_method="pace", ratelimit_pacefactor=0.9, request_timeout=300) else: # the defaults are ratelimit_method='wait', # ratelimit_pacefactor=1.1, request_timeout=300 mastodon = Mastodon(client_id=client_secret, access_token=user_secret, api_base_url=url) return mastodon
def toot(bot, trigger): #bot.say(os.getcwd()) mytoot = trigger.split(' ', 1)[1] try: keys = open(os.getcwd() + "/SECRET_SAUCE/masto.txt", "r") client_id = keys.readline().rstrip() client_secret = keys.readline().rstrip() access_token = keys.readline().rstrip() api_base_url = keys.readline().rstrip() mastodon = Mastodon(client_id, client_secret, access_token, api_base_url) mastodon.toot(mytoot) keys.close() bot.say("OK, I tooted that to " + api_base_url) except: bot.say("It all went to shit, son.")
def connect(type='twitter' ): # connect to twitter API using keys from developer account if type == 'twitter': return twitter.Api(consumer_key=MY_CONSUMER_KEY, consumer_secret=MY_CONSUMER_SECRET, access_token_key=MY_ACCESS_TOKEN_KEY, access_token_secret=MY_ACCESS_TOKEN_SECRET, tweet_mode='extended') elif type == 'mastodon': return Mastodon(client_id=CLIENT_CRED_FILENAME, api_base_url=MASTODON_API_BASE_URL, access_token=USER_ACCESS_FILENAME) return None
def login_mastodon(user): """ Mastodon OAuth authentication process. :return: redirect to city page. """ # get app tokens instance_url = request.forms.get('instance_url') masto_email = request.forms.get('email') masto_pass = request.forms.get('pass') client_id, client_secret = user.get_mastodon_app_keys(instance_url) m = Mastodon(client_id=client_id, client_secret=client_secret, api_base_url=instance_url) try: access_token = m.log_in(masto_email, masto_pass) user.save_masto_token(access_token, instance_url) return city_page( user.get_city(), info='Thanks for supporting decentralized social networks!') except Exception: logger.error('Login to Mastodon failed.', exc_info=True) return dict(error='Login to Mastodon failed.')
def check(self, request, user): """ check if the service is well configured :return: Boolean """ redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(), reverse('mastodon_callback')) us = UserService.objects.get(user=user, name='ServiceMastodon') client_id, client_secret = MastodonAPI.create_app( client_name="TriggerHappy", api_base_url=us.host, redirect_uris=redirect_uris) # get the token by logging in mastodon = MastodonAPI(client_id=client_id, client_secret=client_secret, api_base_url=us.host) try: mastodon.log_in(username=us.username, password=us.password) return True except MastodonIllegalArgumentError as e: return e
def initalize(self): if not os.path.isfile("security_bot_clientcred.txt"): print("Creating app") self.mastodon = Mastodon.create_app( 'security_bot_main', to_file='security_bot_clientcred.txt', api_base_url=self.instance_url) # Fetch access token if I didn't already if not os.path.isfile("security_bot_usercred.txt"): print("Logging in") self.mastodon = Mastodon(client_id='security_bot_clientcred.txt', api_base_url=self.instance_url) email = sys.argv[1] password = sys.argv[2] self.mastodon.log_in(email, password, to_file='security_bot_usercred.txt') self.mastodon = Mastodon(client_id='security_bot_clientcred.txt', access_token='security_bot_usercred.txt', api_base_url=self.instance_url)
def do_post_mastodon(tweet_text, image_file, image_mime_type): if not DO_MASTODON: return '' api = Mastodon( client_secret=CLIENT_SECRET, access_token=ACCESS_TOKEN, api_base_url='https://mastodon.cloud' ) with open(image_file, 'rb') as f: content = f.read(-1) media_id = 0 post_result = api.media_post( media_file=content, mime_type=image_mime_type, description=tweet_text) media_id = int(post_result['id']) if media_id != 0: status = api.status_post(status=tweet_text, media_ids=media_id) else: status = api.status_post(status=tweet_text) return "Tooted: \"{0}\"\n".format(tweet_text)
def __init__(self, logger: Logger, client_id: str, client_secret: str, access_token: str, api_base_url: str, reply_everyone: bool = False): self.logger = logger self.api = MastodonAPI(client_id, client_secret, access_token, api_base_url) self.myself = self.api.account_verify_credentials() self.reply_everyone = reply_everyone self._cached = dict()
def __init__( self, mastodon: Mastodon, hihobot: Hihobot, wait_span: float, myname_list: List[str], ): self.mastodon = mastodon self.hihobot = hihobot self.wait_span = wait_span self.myname_list = myname_list self.me = mastodon.account_verify_credentials()
def get_mastodon_configs() -> dict: instance_url = input("Mastodon instance url: ") (client_id, client_secret) = Mastodon.create_app( 'diadon', api_base_url=instance_url, scopes=['read', 'write'], website='https://github.com/f-person/diadon') api = Mastodon(client_id, client_secret, api_base_url=instance_url) email = input("Email: ") password = getpass() access_token = api.log_in(email, password, scopes=['read', 'write']) return { 'instance_url': instance_url, 'client_id': client_id, 'client_secret': client_secret, 'access_token': access_token }
def createmastodonapp(appname, baseurl, email, password): Mastodon.create_app(appname, api_base_url=baseurl, to_file='pytooter_clientcred.secret') # Then login. This can be done every time, or use persisted. mastodon = Mastodon(client_id='pytooter_clientcred.secret', api_base_url=baseurl) mastodon.log_in(email, password, to_file='pytooter_usercred.secret')
def crosspost(): # Set up Mastodon connection mastodon = Mastodon( client_id = 'pytooter_clientcred.secret', api_base_url = 'https://lgbt.io' ) mastodon.log_in( macreds.username, macreds.password, to_file = 'pytooter_usercred.secret' ) mastodon = Mastodon( client_id = 'pytooter_clientcred.secret', access_token = 'pytooter_usercred.secret', api_base_url = macreds.base_url ) # Set up Twitter connection auth = tweepy.OAuthHandler(twcreds.consumer_key, twcreds.consumer_secret) auth.set_access_token(twcreds.access_token, twcreds.access_token_secret) api = tweepy.API(auth) # Set up files idfile = "twcache.txt" idfromfile = open(idfile, 'r') lastid = idfromfile.read() #print("Last status ID read from file: " + laststatus) # Get tweets since last status recorded in idfile try: status = api.user_timeline(since_id=lastid, count=20, ) except: status = api.user_timeline(count=20) # Loop through tweets for i in reversed(status): # Toot if (i.in_reply_to_user_id == 53925971 or not i.in_reply_to_user_id) and i.is_quote_status == False and i.retweeted == False: mastodon.toot(i.text) #print(i.text) # Update idfile with ID of last successfully tooted tweet lastid = i.id idtofile = open(idfile, 'w') idtofile.write(str(lastid)) idtofile.close()
def init_twitter_api(): global api if (os.path.isfile('clientcred.secret') == False): Mastodon.create_app('ace-attorney', api_base_url=keys['domain'], to_file='clientcred.secret') if (os.path.isfile('usercred.secret') == False): m = Mastodon(client_id='clientcred.secret', api_base_url=keys['domain']) m.log_in(keys['mail'], keys['password'], to_file='usercred.secret') api = Mastodon(access_token='usercred.secret', api_base_url=keys['domain'])
def authorize(self): """ Tries to authorize via OAuth API, and save access token. If it fails fallsback to username and password. """ url = self.url client_secret = self.client_secret user_secret = self.user_secret scopes = self.scopes print("This app needs access to your Mastodon account.") mastodon = Mastodon(client_id=client_secret, api_base_url=url) url = mastodon.auth_request_url(client_id=client_secret, scopes=scopes) print("Visit the following URL and authorize the app:") print(url) print("Then paste the access token here:") token = sys.stdin.readline().rstrip() try: # on the very first login, --pace has no effect mastodon.log_in(code=token, to_file=user_secret, scopes=scopes) except Exception: print( "Sadly, that did not work. On some sites, this login mechanism" ) print("(namely OAuth) seems to be broken. There is an alternative") print( "if you are willing to trust us with your password just this") print("once. We need it just this once in order to get an access") print( "token. We won't save it. If you don't want to try this, use") print("Ctrl+C to quit. If you want to try it, please provide your") print("login details.") sys.stdout.write("Email: ") sys.stdout.flush() email = sys.stdin.readline().rstrip() sys.stdout.write("Password: ") sys.stdout.flush() password = sys.stdin.readline().rstrip() # on the very first login, --pace has no effect mastodon.log_in(username=email, password=password, to_file=user_secret, scopes=scopes) return mastodon
def crawl(self, user): """ Crawl mentions from Mastodon. :return: list of statuses """ mentions = [] try: m = Mastodon(*user.get_masto_credentials()) except TypeError: # logger.error("No Mastodon Credentials in database.", exc_info=True) return mentions try: notifications = m.notifications() except Exception: logger.error("Unknown Mastodon API Error.", exc_info=True) return mentions for status in notifications: if (status['type'] == 'mention' and not user.toot_is_seen(status['status']['uri'])): # save state user.toot_witness(status['status']['uri']) # add mention to mentions text = re.sub(r'<[^>]*>', '', status['status']['content']) text = re.sub( "(?<=^|(?<=[^a-zA-Z0-9-_.]))@([A-Za-z]+[A-Za-z0-9-_]+)", "", text) if status['status']['visibility'] == 'public': mentions.append( Report(status['account']['acct'], self, text, status['status']['id'], status['status']['created_at'])) else: mentions.append( Report(status['account']['acct'], 'mastodonPrivate', text, status['status']['id'], status['status']['created_at'])) return mentions
def _execute(self, options, args): """Announce today's post on Mastodon""" self.site.scan_posts() today_post = [ x for x in self.site.timeline if x.date.date() == datetime.today().date() ] if len(today_post) > 0: meta = get_meta(today_post[0], 'fr') content = list([today_post[0].title()]) content.append(today_post[0].description()) [content.append(x) for x in meta[0]['references']] content.insert(0, '#laminuteculturelle') content.append( 'archives: https://www.mad-scientists.net/la-minute-culturelle/' ) content_str = "\n".join(content) mastodon = Mastodon(access_token=options['mastodon-token'], api_base_url=options['mastodon-node']) mastodon.toot(content_str) return 0
def check(self, request, user): """ check if the service is well configured :return: Boolean """ redirect_uris = '%s://%s%s' % (request.scheme, request.get_host(), reverse('mastodon_callback')) us = UserService.objects.get(user=user, name='ServiceMastodon') client_id, client_secret = MastodonAPI.create_app( client_name="TriggerHappy", api_base_url=us.host, redirect_uris=redirect_uris) # get the token by logging in mastodon = MastodonAPI( client_id=client_id, client_secret=client_secret, api_base_url=us.host ) try: mastodon.log_in(username=us.username, password=us.password) return True except MastodonIllegalArgumentError as e: return e
def get_service(hass, config, discovery_info=None): """Get the Mastodon notification service.""" from mastodon import Mastodon from mastodon.Mastodon import MastodonUnauthorizedError client_id = config.get(CONF_CLIENT_ID) client_secret = config.get(CONF_CLIENT_SECRET) access_token = config.get(CONF_ACCESS_TOKEN) base_url = config.get(CONF_BASE_URL) try: mastodon = Mastodon( client_id=client_id, client_secret=client_secret, access_token=access_token, api_base_url=base_url, ) mastodon.account_verify_credentials() except MastodonUnauthorizedError: _LOGGER.warning("Authentication failed") return None return MastodonNotificationService(mastodon)
def __init__(self, access_token, since_at, instance_url, msg_template='', debug_mode=True, account_id=1): self.instance_url = instance_url self.msg_template = Template(msg_template) self.client = Mastodon( access_token=access_token, api_base_url=self.instance_url ) self.since_at = since_at self.debug_mode = debug_mode self.log = logging.getLogger() if self.debug_mode: self.log.setLevel(logging.DEBUG) else: self.log.setLevel(logging.INFO) ch = logging.StreamHandler(sys.stdout) self.log.addHandler(ch) 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 set_mastodon_keys(conn): msg = "In order to use Mastodon, we need to and can generate the keys here." + linefeed + linefeed print(msg) mastodon_instance_url = input("First, I need the url of the instance your bot account is on (EX: https://botsin.space): ") mastodon_bot_app_name = input("Now I need to know what you want to call the app. Try to make it unique (EX: my_aprs_bot): ") mastodon_username = input("Now I need the username for the bot account: ") mastodon_password = input("Finally I need the password for the bot account: ") client_keys = Mastodon.create_app(mastodon_bot_app_name, scopes=['read', 'write'], api_base_url=mastodon_instance_url) client_id = client_keys[0] client_secret = client_keys[1] mastodon_api = Mastodon(client_id, client_secret, api_base_url = mastodon_instance_url) access_token = mastodon_api.log_in(mastodon_username, mastodon_password, scopes=["read", "write"]) sql = "update apikeys set mastodon_client_id = '" + client_id + "', " sql = sql + "mastodon_client_secret = '" + client_secret + "', " sql = sql + "mastodon_api_base_url = '" + mastodon_instance_url + "', " sql = sql + "mastodon_user_access_token = '" + access_token + "';" run_sql(conn,sql)
def __init__(self): self.logger = logging.getLogger(__name__) self.project_root = os.path.abspath(os.path.dirname(__file__)) self.config_file = os.path.join(self.project_root, "config.cfg") self.load_config() if self.verbose: self.logger.setLevel(logging.INFO) self.redis = redis.Redis( host=self.redis_hostname, port=self.redis_port, password=self.redis_password, charset="utf-8", decode_responses=True, ) self.twitter_api = None self.mastodon_api = None if self.twitter_consumer_key: self.twitter_api = twitter.Api( consumer_key=self.twitter_consumer_key, consumer_secret=self.twitter_consumer_secret, access_token_key=self.twitter_access_token, access_token_secret=self.twitter_access_token_secret, ) if self.mastodon_client_id: self.mastodon_api = Mastodon( client_id=self.mastodon_client_id, client_secret=self.mastodon_client_secret, access_token=self.mastodon_access_token, api_base_url=self.mastodon_api_base_url, ) try: self.local_tz = pytz.timezone(self.timezone) except pytz.exceptions.UnknownTimeZoneError: self.error("Unknown or no timezone in settings: %s" % self.timezone) sys.exit(0)
def start(self, folder=".") -> None: "This actually runs the bot" self.mastodon = Mastodon( client_id=os.path.join(folder, 'pyborg_mastodon_clientcred.secret'), access_token=os.path.join(folder, 'pyborg_mastodon_usercred.secret'), api_base_url=self.settings['mastodon']['base_url'] ) self.my_id = self.mastodon.account_verify_credentials()['id'] while True: tl = self.mastodon.timeline() toots: List[Dict] = [] mentions = [notif['status'] for notif in self.mastodon.notifications() if notif['type'] == "mention"] toots.extend(tl) toots.extend(mentions) self.handle_toots(toots) self.last_look = arrow.utcnow() logger.debug("Sleeping for {} seconds".format(self.settings['mastodon']['cooldown'])) time.sleep(self.settings['mastodon']['cooldown'])
return True if __name__ == '__main__': from mastodon import Mastodon try: base_url, email, password, clientname, clientcred, usercred = sys.argv[1:] except: print("Usage: %s base_url email password clientname clientcredsfile usercredsfile" % sys.argv[0]) sys.exit(2) if not os.path.isfile(clientcred): Mastodon.create_app( clientname, to_file = clientcred, scopes = [ 'read', 'write' ], api_base_url = base_url) if not os.path.isfile(usercred): mastodon_api = Mastodon( client_id = clientcred, api_base_url = base_url) mastodon_api.log_in( email, password, to_file = usercred, scopes = [ 'read', 'write' ], )
sys.exit(0) # Load secrets from secrets file secrets_filepath = "secrets/secrets.txt" uc_client_id = get_parameter("uc_client_id", secrets_filepath) uc_client_secret = get_parameter("uc_client_secret", secrets_filepath) uc_access_token = get_parameter("uc_access_token", secrets_filepath) # Load configuration from config file config_filepath = "config.txt" mastodon_hostname = get_parameter("mastodon_hostname", config_filepath) # E.g., mastodon.social # Initialise Mastodon API mastodon = Mastodon( client_id = uc_client_id, client_secret = uc_client_secret, access_token = uc_access_token ) # Initialise access headers headers={ 'Authorization': 'Bearer %s'%uc_access_token } ############################################################################### # GET THE DATA ############################################################################### # Get current timestamp ts = int(time.time()) # Get the /about/more page from the server
# You can e.g. use https://takahashim.github.io/mastodon-access-token/ # to generate your access-key. #--------------------------------------------- ######################################################### # no need to change anything after here #--------------------------------------------- # # # M A I N L O O P # # # # #--------------------------------------------- # picdir = os.getcwd() print('picture directory is %s' % (picdir)) mastodon = Mastodon( access_token = access_token, api_base_url = podurl ) # check if there is my archive_posted.txt in picture directory archive_path = '%s/%s' % (picdir, '0archive_mastodon.txt') print(archive_path) ismylogthere = os.path.exists(archive_path) if ismylogthere == False: print('creating my archive-log in %s' % (archive_path)) f=open(archive_path,"w") f.close() # read already posted pics from archive_posted.txt archiveposted = open(archive_path).read()
# o8o o888o `Y888""8o o888o o888o o888o o888ooooood8 `Y8bod8P' `Y8bod8P' 888bod8P' # 888 # o888o # TODO: remove class class Ask: def __init__(self, message, sender, askid): self.sender = sender self.askid = askid self.message = message.encode('utf-8', 'ignore') self.message = filter_message(self.message) self.message = Message(self.message, self.sender) # Create Mastodon API instance mastodon = Mastodon( access_token = 'emma_usercred.secret', api_base_url = 'https://botsin.space' ) # Create listener class Listener(StreamListener): """ Listens for Mastodon activity Class Variables message str String representation of the Message sender str Username of person who sent the Message tootID int ID of the Toot so that we can reply reply str Emma's reply to the Message """ def on_notification(self, status): if status.type == 'mention':
class Tweeter: twitter_consumer_key = "" twitter_consumer_secret = "" twitter_access_token = "" twitter_access_token_secret = "" mastodon_client_id = "" mastodon_client_secret = "" mastodon_access_token = "" mastodon_api_base_url = "https://mastodon.social" # 1 will output stuff. verbose = 0 # How many years ahead are we of the dated tweets? years_ahead = 0 # No matter when we last ran this script, we'll only ever post # tweets from within the past max_time_window minutes. max_time_window = 20 # Which timezone are we using to check when tweets should be sent? # eg 'Europe/London'. # See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones for # possible strings. timezone = "Europe/London" # Only used if we're using Redis. redis_hostname = "localhost" redis_port = 6379 redis_password = None # Will be the redis.Redis() object: redis = None def __init__(self): self.logger = logging.getLogger(__name__) self.project_root = os.path.abspath(os.path.dirname(__file__)) self.config_file = os.path.join(self.project_root, "config.cfg") self.load_config() if self.verbose: self.logger.setLevel(logging.INFO) self.redis = redis.Redis( host=self.redis_hostname, port=self.redis_port, password=self.redis_password, charset="utf-8", decode_responses=True, ) self.twitter_api = None self.mastodon_api = None if self.twitter_consumer_key: self.twitter_api = twitter.Api( consumer_key=self.twitter_consumer_key, consumer_secret=self.twitter_consumer_secret, access_token_key=self.twitter_access_token, access_token_secret=self.twitter_access_token_secret, ) if self.mastodon_client_id: self.mastodon_api = Mastodon( client_id=self.mastodon_client_id, client_secret=self.mastodon_client_secret, access_token=self.mastodon_access_token, api_base_url=self.mastodon_api_base_url, ) try: self.local_tz = pytz.timezone(self.timezone) except pytz.exceptions.UnknownTimeZoneError: self.error("Unknown or no timezone in settings: %s" % self.timezone) sys.exit(0) def load_config(self): if os.path.isfile(self.config_file): self.load_config_from_file() else: self.load_config_from_env() def load_config_from_file(self): config = configparser.ConfigParser() config.read(self.config_file) settings = config["DEFAULT"] self.twitter_consumer_key = settings["TwitterConsumerKey"] self.twitter_consumer_secret = settings["TwitterConsumerSecret"] self.twitter_access_token = settings["TwitterAccessToken"] self.twitter_access_token_secret = settings["TwitterAccessTokenSecret"] self.mastodon_client_id = settings["MastodonClientId"] self.mastodon_client_secret = settings["MastodonClientSecret"] self.mastodon_access_token = settings["MastodonAccessToken"] self.mastodon_api_base_url = settings["MastodonApiBaseUrl"] self.verbose = int(settings.get("Verbose", self.verbose)) self.years_ahead = int(settings.get("YearsAhead", self.years_ahead)) self.timezone = settings.get("Timezone", self.timezone) self.max_time_window = int(settings.get("MaxTimeWindow", self.max_time_window)) self.redis_hostname = settings.get("RedisHostname", self.redis_hostname) self.redis_port = int(settings.get("RedisPort", self.redis_port)) self.redis_password = settings.get("RedisPassword", self.redis_password) def load_config_from_env(self): self.twitter_consumer_key = os.environ.get("TWITTER_CONSUMER_KEY") self.twitter_consumer_secret = os.environ.get("TWITTER_CONSUMER_SECRET") self.twitter_access_token = os.environ.get("TWITTER_ACCESS_TOKEN") self.twitter_access_token_secret = os.environ.get("TWITTER_ACCESS_TOKEN_SECRET") self.mastodon_client_id = os.environ.get("MASTODON_CLIENT_ID") self.mastodon_client_secret = os.environ.get("MASTODON_CLIENT_SECRET") self.mastodon_access_token = os.environ.get("MASTODON_ACCESS_TOKEN") self.mastodon_api_base_url = os.environ.get("MASTODON_API_BASE_URL") self.verbose = int(os.environ.get("VERBOSE", self.verbose)) self.years_ahead = int(os.environ.get("YEARS_AHEAD", self.years_ahead)) self.timezone = os.environ.get("TIMEZONE", self.timezone) self.max_time_window = int( os.environ.get("MAX_TIME_WINDOW", self.max_time_window) ) redis_url = urlparse.urlparse(os.environ.get("REDIS_URL")) self.redis_hostname = redis_url.hostname self.redis_port = redis_url.port self.redis_password = redis_url.password def start(self): # eg datetime.datetime(2014, 4, 25, 18, 59, 51, tzinfo=<UTC>) last_run_time = self.get_last_run_time() # We need to have a last_run_time set before we can send any tweets. # So the first time this is run, we can't do anythning. if last_run_time is None: self.set_last_run_time() logging.warning( "No last_run_time in database.\n" "This must be the first time this has been run.\n" "Settinge last_run_time now.\n" "Run the script again in a minute or more, and it should work." ) sys.exit(0) local_time_now = datetime.datetime.now(self.local_tz) year_dir = str(int(local_time_now.strftime("%Y")) - self.years_ahead) month_file = "%s.txt" % local_time_now.strftime("%m") # eg tweets/1660/01.txt path = os.path.join(self.project_root, "tweets", year_dir, month_file) with open(path) as file: lines = [line.strip() for line in file] all_tweets = self.get_all_tweets(lines) tweets_to_send = self.get_tweets_to_send( all_tweets, last_run_time, local_time_now ) self.set_last_run_time() # We want to tweet the oldest one first, so reverse list: self.send_tweets(tweets_to_send[::-1]) # And the same with Mastodon toots: self.send_toots(tweets_to_send[::-1]) def get_all_tweets(self, lines): """ Go through all the lines in the file and, for any that contain valid tweet data, add them to a list to return. Returns a list of dicts, each one data about a tweet. """ tweets = [] for line in lines: if line != "": tweet = self.parse_tweet_line(line) if tweet: tweets.append(tweet) else: # An invalid line format or invalid tweet time. continue return tweets def get_tweets_to_send(self, all_tweets, last_run_time, local_time_now): """ Work out which of all the tweets in the month need to be sent. all_tweets - List of dicts, one per tweet last_run_time - datetime object for when the script was last run local_time_now - timezone-aware datetime for now Returns a list of dicts of the tweets that need sending. """ tweets_to_send = [] local_last_run_time = last_run_time.astimezone(self.local_tz) for n, tweet in enumerate(all_tweets): local_modern_tweet_time = self.modernize_time(tweet["time"]) now_minus_tweet = (local_time_now - local_modern_tweet_time).total_seconds() tweet_minus_lastrun = ( local_modern_tweet_time - local_last_run_time ).total_seconds() if now_minus_tweet > 0: # Tweet is earlier than now. if tweet_minus_lastrun >= 0 and now_minus_tweet <= ( self.max_time_window * 60 ): # And Tweet is since we last ran and within our max time window. if tweet["is_reply"] is True: # Get the time of the previous tweet, which is the one # this tweet is replying to. prev_tweet = all_tweets[n + 1] in_reply_to_time = prev_tweet["time"] else: in_reply_to_time = None tweet["in_reply_to_time"] = in_reply_to_time self.log( "Preparing: '{}...' " "timed {}, " "is_reply: {}, " "local_last_run_time: {}, " "local_modern_tweet_time: {}, " "in_reply_to_time: {}".format( tweet["text"][:20], tweet["time"], tweet["is_reply"], local_last_run_time, local_modern_tweet_time, in_reply_to_time, ) ) tweets_to_send.append(tweet) else: break return tweets_to_send def parse_tweet_line(self, line): """ Given one line from a text file, try to parse it out into time and tweet text. Returns a dict of data if successful, otherwise False A line is like one of: 1666-02-09 14:08 This is my text 1666-02-09 14:08 This is my text 1666-02-09 14:08 r This is my text 1666-02-09 14:08 r This is my text """ tweet = False pattern = r""" ^ # Start of line ( \d\d\d\d-\d\d-\d\d # Date like 1666-02-09 \s \d\d\:\d\d # Time like 14:08 ) # GROUP 1: Date and time (?: # Don't count this group \s # A space before the 'r' ( \w # A literal 'r' (probably). ) # GROUP 2: r (or None) )? # The 'r ' is optional \s+ # One or more spaces (.*?) # The tweet text $ # End of line """ line_match = re.search(pattern, line, re.VERBOSE) if line_match: [tweet_time, tweet_kind, tweet_text] = line_match.groups() # Check the time maps to a valid modern time: local_modern_tweet_time = self.modernize_time(tweet_time) if local_modern_tweet_time: if tweet_kind == "r": is_reply = True else: is_reply = False tweet = { "time": tweet_time, "text": tweet_text.strip(), "is_reply": is_reply, } return tweet def set_last_run_time(self): """ Set the 'last run time' in the database to now, in UTC. """ time_now = datetime.datetime.now(pytz.timezone("UTC")) self.redis.set("last_run_time", time_now.strftime("%Y-%m-%d %H:%M:%S")) def get_last_run_time(self): """ Get the 'last run time' from the database. Returns, eg datetime.datetime(2014, 4, 25, 18, 59, 51, tzinfo=<UTC>) or `None` if it isn't currently set. """ last_run_time = self.redis.get("last_run_time") if last_run_time: return datetime.datetime.strptime( last_run_time, "%Y-%m-%d %H:%M:%S" ).replace(tzinfo=pytz.timezone("UTC")) else: return None def modernize_time(self, t): """ Takes a time string like `1661-04-28 12:34` and translates it to the modern equivalent in local time, eg: datetime.datetime( 2014, 4, 28, 12, 34, 00, tzinfo=<DstTzInfo 'Europe/London' BST+1:00:00 DST>) Returns False if something goes wrong. """ naive_time = datetime.datetime.strptime(t, "%Y-%m-%d %H:%M") try: local_modern_time = self.local_tz.localize( datetime.datetime( naive_time.year + self.years_ahead, naive_time.month, naive_time.day, naive_time.hour, naive_time.minute, naive_time.second, ) ) except ValueError as e: # Unless something else is wrong, it could be that naive_time # is 29th Feb and there's no 29th Feb in the current, modern, year. self.log("Skipping %s as can't make a modern time from it: %s" % (t, e)) local_modern_time = False return local_modern_time def send_tweets(self, tweets): """ `tweets` is a list of tweets to post now. Each element is a dict of: 'time' (e.g. '1666-02-09 12:35') 'text' (e.g. "This is my tweet") 'is_reply_to' (e.g. '1666-02-09 12:34' or '') 'in_reply_to_time' (e.g. '1666-02-09 12:33', or None) Should be in the order in which they need to be posted. """ if self.twitter_api is None: self.log("No Twitter Consumer Key set; not tweeting") return for tweet in tweets: previous_status_id = None if tweet["in_reply_to_time"] is not None: # This tweet is a reply, so check that it's a reply to the # immediately previous tweet. # It *should* be, but if something went wrong, maybe not. previous_status_time = self.redis.get("previous_tweet_time") if tweet["in_reply_to_time"] == previous_status_time: previous_status_id = self.redis.get("previous_tweet_id") self.log( "Tweeting: {} [{} characters]".format(tweet["text"], len(tweet["text"])) ) try: status = self.twitter_api.PostUpdate( tweet["text"], in_reply_to_status_id=previous_status_id ) except twitter.TwitterError as e: self.error(e) else: # Set these so that we can see if the next tweet is a reply # to this one, and then one ID this one was. self.redis.set("previous_tweet_time", tweet["time"]) self.redis.set("previous_tweet_id", status.id) time.sleep(2) def send_toots(self, tweets): """ `tweets` is a list of toot texts to post now. Each element is a dict of: 'time' (e.g. '1666-02-09 12:35') 'text' (e.g. "This is my toot") 'is_reply' boolean; is this a reply to the previous toot. 'in_reply_to_time' (e.g. '1666-02-09 12:33', or None) Should be in the order in which they need to be posted. """ if self.mastodon_api is None: self.log("No Mastodon Client ID set; not tooting") return for tweet in tweets: previous_status_id = None if tweet["in_reply_to_time"] is not None: # This tweet is a reply, so check that it's a reply to the # immediately previous toot. # It *should* be, but if something went wrong, maybe not. previous_status_time = self.redis.get("previous_toot_time") if tweet["in_reply_to_time"] == previous_status_time: previous_status_id = self.redis.get("previous_toot_id") self.log( "Tooting: {} [{} characters]".format(tweet["text"], len(tweet["text"])) ) try: status = self.mastodon_api.status_post( tweet["text"], in_reply_to_id=previous_status_id ) except MastodonError as e: self.error(e) else: # Set these so that we can see if the next tweet is a reply # to this one, and then one ID this one was. self.redis.set("previous_toot_time", tweet["time"]) self.redis.set("previous_toot_id", status.id) time.sleep(2) def log(self, s): self.logger.info(s) def error(self, s): self.logger.error(s)
class PyborgMastodon(object): """it does toots""" # todo: attrs def __init__(self, conf_file): self.toml_file = conf_file self.settings = toml.load(conf_file) self.last_look = arrow.get(self.settings['mastodon']['last_look']) self.multiplexing = True self.multi_server = self.settings['pyborg']['multi_server'] def teardown(self) -> None: self.settings['mastodon']['last_look'] = self.last_look.datetime with open(self.toml_file, "w") as f: toml.dump(self.settings, f) logging.info("saved mastodon config at: %s", self.toml_file) if not self.multiplexing: raise NotImplementedError("Use multiplexing.") # self.pyborg.save_all() def learn(self, body) -> None: if self.multiplexing: try: ret = requests.post("http://{}:2001/learn".format(self.multi_server), data={"body": body}) if ret.status_code > 499: logger.error("Internal Server Error in pyborg_http. see logs.") else: ret.raise_for_status() except requests.exceptions.ConnectionError as e: logger.exception(e) self.teardown() sys.exit(17) else: raise NotImplementedError("Use multiplexing.") # self.pyborg.learn(body) def reply(self, body) -> Optional[str]: if self.multiplexing: try: ret = requests.post("http://{}:2001/reply".format(self.multi_server), data={"body": body}) if ret.status_code == requests.codes.ok: reply = ret.text logger.debug("got reply: %s", reply) elif ret.status_code > 499: logger.error("Internal Server Error in pyborg_http. see logs.") return None else: ret.raise_for_status() return reply except requests.exceptions.ConnectionError as e: logger.exception(e) self.teardown() sys.exit(17) else: raise NotImplementedError("use multiplexing.") # return self.pyborg.reply(body) def should_reply_direct(self, usern) -> bool: should_reply = [] should_reply.extend([a['acct'] for a in self.mastodon.account_followers(self.my_id)]) # is this cached? return usern in should_reply def is_reply_to_me(self, item: Dict) -> bool: logger.debug(item) try: if item["in_reply_to_account_id"] == self.my_id: return True else: return False except KeyError: if item["type"] == "mention": if any([True for mention in item["mentions"] if mention['id'] == self.my_id]): return True else: # Is this actually possible? return False else: return False def handle_toots(self, toots: List[Dict]) -> None: for item in toots: # logger.debug(arrow.get(item["created_at"]) > self.last_look) logger.debug(item['content']) logger.debug(arrow.get(item["created_at"]) - self.last_look) if (arrow.get(item["created_at"]) > self.last_look) and item["account"]["id"] is not self.my_id: logger.info("Got New Toot: {}".format(item)) fromacct = item['account']['acct'] # to check if we've banned them? parsed_html = lxml.html.fromstring(item['content']) body = parsed_html.text_content() if self.settings['pyborg']['learning']: self.learn(body) reply = self.reply(body) if reply: logger.debug("got reply from http: %s", reply) if (self.should_reply_direct(fromacct) or self.is_reply_to_me(item)): self.mastodon.status_post(reply, in_reply_to_id=item['id']) else: logger.info("Got reply but declined to toot. recv'd body: %s", body) else: logger.info("Couldn't toot.") def start(self, folder=".") -> None: "This actually runs the bot" self.mastodon = Mastodon( client_id=os.path.join(folder, 'pyborg_mastodon_clientcred.secret'), access_token=os.path.join(folder, 'pyborg_mastodon_usercred.secret'), api_base_url=self.settings['mastodon']['base_url'] ) self.my_id = self.mastodon.account_verify_credentials()['id'] while True: tl = self.mastodon.timeline() toots: List[Dict] = [] mentions = [notif['status'] for notif in self.mastodon.notifications() if notif['type'] == "mention"] toots.extend(tl) toots.extend(mentions) self.handle_toots(toots) self.last_look = arrow.utcnow() logger.debug("Sleeping for {} seconds".format(self.settings['mastodon']['cooldown'])) time.sleep(self.settings['mastodon']['cooldown'])
def send_toot(ticket, config): logging.info("toot the release") target = '' if ticket.voctoweb_enable and ticket.profile_voctoweb_enable: target = config['voctoweb']['instance_name'] if ticket.youtube_enable and ticket.profile_youtube_enable: if len(target) > 1: target += ' and ' target += 'YouTube' msg = ' has been released on ' + target title = ticket.title if len(title) >= (500 - len(msg)): title = title[0:len(msg)] message = title + msg if ticket.voctoweb_enable and ticket.profile_voctoweb_enable: voctoweb_url = ' ' + config['voctoweb']['frontend_url'] + '/v/' + ticket.slug if len(voctoweb_url) <= (500 - len(message)): message = message + voctoweb_url if ticket.youtube_enable and ticket.profile_youtube_enable and len(ticket.youtube_urls['YouTube.Url0']) <= (500 - len(message)): message = message + ' ' + ticket.youtube_urls['YouTube.Url0'] try: # check if we already have our client token and secret and if not get a new one if not Path('./mastodon_clientcred.secret').exists(): logging.debug('no mastodon client credentials found, get fresh ones') Mastodon.create_app( 'voctopublish', api_base_url=config['mastodon']['api_base_url'], to_file='mastodon_clientcred.secret' ) else: logging.debug('Using exisiting Mastodon client credentials') mastodon = Mastodon( client_id='mastodon_clientcred.secret', api_base_url=config['mastodon']['api_base_url'] ) # check if we already have an access token, if not get a fresh one if not Path('./mastodon_usercred.secret').exists(): logging.debug('no mastodon user credentials found, getting a fresh token') mastodon.log_in( config['mastodon']['email'], config['mastodon']['password'], to_file='mastodon_usercred.secret' ) else: logging.debug('Using existing Mastodon user token') # Create actual API instance mastodon = Mastodon( access_token='mastodon_usercred.secret', api_base_url=config['mastodon']['api_base_url'] ) mastodon.toot(message) except Exception as e_: # we don't care if tooting fails here. logging.error('Tooting failed: ' + str(e_))
last_id_file = Path('.') / 'last_id.txt' last_id = 0 if IS_DOCKER: last_id_file = Path('/data') / 'last_id' if last_id_file.is_file(): with open(last_id_file) as f: last_id = int(f.read()) print('Botvenon is starting...') print('Welcoming any users after id %d' % last_id) mastodon = Mastodon( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, access_token=ACCESS_TOKEN, api_base_url=INSTANCE_BASE) user = mastodon.account_verify_credentials() # Get the current user followers = mastodon.account_followers(user) # Get the latest followers # print( # f'''Followed by: {account.username} # (Acct value: {account.acct}, id: {account.id})''') while True: for account in mastodon.account_followers(user): if is_local_account(account) and account.id > last_id and not account.bot: