social media crossposting tool. 3rd time's the charm
mastodon misskey crossposting bluesky
1import asyncio 2import json 3import queue 4import threading 5from pathlib import Path 6from typing import Callable 7 8import env 9from database.migrations import DatabaseMigrator 10from registry import create_input_service, create_output_service 11from registry_bootstrap import bootstrap 12from util.util import LOGGER, read_env 13 14 15def main() -> None: 16 data = Path(env.DATA_DIR) 17 18 if not data.exists(): 19 data.mkdir(parents=True) 20 21 settings_path = data.joinpath("settings.json") 22 database_path = data.joinpath("db.sqlite") 23 24 if not settings_path.exists(): 25 LOGGER.info("First launch detected! Creating %s and exiting!", settings_path) 26 return 27 28 migrator = DatabaseMigrator(database_path, Path(env.MIGRATIONS_DIR)) 29 try: 30 migrator.migrate() 31 except Exception: 32 LOGGER.exception("Failed to migrate database!") 33 return 34 finally: 35 migrator.close() 36 37 LOGGER.info("Bootstrapping registries...") 38 bootstrap() 39 40 LOGGER.info("Loading settings...") 41 42 with open(settings_path) as f: 43 settings = json.load(f) 44 read_env(settings) 45 46 if "input" not in settings: 47 raise KeyError("No `input` sepcified in settings!") 48 if "outputs" not in settings: 49 raise KeyError("No `outputs` spicified in settings!") 50 51 input = create_input_service(database_path, settings["input"]) 52 outputs = [ 53 create_output_service(database_path, data) for data in settings["outputs"] 54 ] 55 56 LOGGER.info("Starting task worker...") 57 58 def worker(task_queue: queue.Queue[Callable[[], None] | None]): 59 while True: 60 task = task_queue.get() 61 if task is None: 62 break 63 64 try: 65 task() 66 except Exception: 67 LOGGER.exception("Exception in worker thread!") 68 finally: 69 task_queue.task_done() 70 71 task_queue: queue.Queue[Callable[[], None] | None] = queue.Queue() 72 thread = threading.Thread(target=worker, args=(task_queue,), daemon=True) 73 thread.start() 74 75 LOGGER.info("Connecting to %s...", "TODO") # TODO 76 try: 77 asyncio.run(input.listen(outputs, lambda c: task_queue.put(c))) 78 except KeyboardInterrupt: 79 LOGGER.info("Stopping...") 80 81 task_queue.join() 82 task_queue.put(None) 83 thread.join() 84 85 86if __name__ == "__main__": 87 main()