diff --git a/toota-palooza/cli.py b/toota-palooza/cli.py index e12b95e..1fc5bc8 100644 --- a/toota-palooza/cli.py +++ b/toota-palooza/cli.py @@ -9,46 +9,50 @@ __version__ = '1.0' __copyright__ = 'Copyright © 2022 Paco Hope. See LICENSE for details.' from mastodon import Mastodon -from dotenv import load_dotenv +import toml import os import time import argparse import sys -from pprint import pprint -# import toota-palooza -class Server(Mastodon): - dotenv_loaded = False +class Tooter(Mastodon): + credentials: dict = {} + hostname: str = '' - def __init__(self): - self.maybe_load_dotenv() - - self.client_id = '.toota-palooza.env' - self.hostname = os.getenv('MD_HOST') - self.username = os.getenv('MD_USER') - self.passwd = os.getenv('MD_PASS') - self.to_file = '.toota-palooza-usercred.env' + def __init__(self, name: str): + cred_dict = self.credentials[name] + self.username = cred_dict['addr'] + self.password = cred_dict['pass'] + self.client_id = f'.toota-palooza.env' + self.cred_file = f'.toota-palooza-usercred-{name}.env' super().__init__(client_id=self.client_id, api_base_url=self.hostname) self.log_in( self.username, - self.passwd, - to_file=self.to_file + self.password, + to_file=self.cred_file ) - def post(self, message): - self.status_post(message, visibility='public') - @classmethod - def maybe_load_dotenv(cls): - if not cls.dotenv_loaded: - load_dotenv() - cls.dotenv_loaded = True + def load_credentials(cls, file: str) -> None: + as_dict = toml.load(file) + try: + cls.hostname = as_dict.pop('host') + except KeyError: + raise KeyError('must provide a hostname') + for username, fields in as_dict.items(): + if not isinstance(fields, dict): + raise TypeError(f'{username} has no key/value pairs') + if 'addr' not in fields: + raise KeyError(f'`addr` field missing from {username}') + if 'pass' not in fields: + raise KeyError(f'`pass` field missing from {username}') + cls.credentials = as_dict -def check_public_timeline(server): +def check_public_timeline(tooter: Tooter): """Do one run. Connect to the database, connect to the server, get the public timeline. Look at users and check to see if any are potential impersonators. Then exit.""" @@ -64,9 +68,9 @@ def check_public_timeline(server): userid_list = {} total = 0 calls = 0 - domain_def = server.hostname.split('/')[2] + domain_def = tooter.hostname.split('/')[2] while total < max_posts: - timeline_list = server.timeline(timeline='public', limit=chunk_size) + timeline_list = tooter.timeline(timeline='public', limit=chunk_size) calls += 1 for post in timeline_list: userid = post.account.acct @@ -81,28 +85,27 @@ def check_public_timeline(server): userid_list[userid] = (username, domain, post.account.display_name, post.account.bot, post.url) - if len(timeline_list) == 0: + posts_indexed = len(timeline_list) + if posts_indexed == 0: # We got fewer than we asked for. Drop out of the loop. break - # record how many we did, and go again. - total += len(timeline_list) - timeline_list.clear() + total += posts_indexed # Ok, we got them all, time to insert return (f'{calls} calls to get {total} posts,' +f' {len(userid_list)} users processed') -def daemon_main(): +def daemon_main(tooter: Tooter): """Run from a command line.""" while True: # do a thing time.sleep(600) -def once(server): +def once(tooter: Tooter): """Run from a command line.""" - message = check_public_timeline(server) - server.post(message) + message = check_public_timeline(tooter) + tooter.toot(message) return 0 def main(): @@ -114,12 +117,14 @@ def main(): help='Run once and exit. Default is to run as a daemon.') args = parser.parse_args() - server = Server() + Tooter.load_credentials('users.toml') if args.once: - return once(server) + t = Tooter('nick') + once(t) + return 0 - daemon_main(server) + daemon_main(t) if __name__ == '__main__': sys.exit(main()) \ No newline at end of file