From 27b0d78116fdfd4de0e316d240d903e8eadd58ee Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Sun, 30 Aug 2020 15:11:50 +0400 Subject: [PATCH] Implement configurable repost routing from TG to Mastodon --- bridge.py | 68 ++++++++++++++++++++++++++++++++-------------- sample.config.toml | 33 ++++++++++++++++------ 2 files changed, 71 insertions(+), 30 deletions(-) diff --git a/bridge.py b/bridge.py index 657201d..236047b 100644 --- a/bridge.py +++ b/bridge.py @@ -1,27 +1,38 @@ +import argparse import asyncio +import logging import os import uuid -from io import BytesIO import toml -import argparse from mastodon import Mastodon from telethon import TelegramClient, events -from telethon.events.common import EventBuilder -from telethon.tl.functions.channels import JoinChannelRequest, GetMessagesRequest +from telethon.tl.functions.channels import JoinChannelRequest from telethon.tl.functions.contacts import ResolveUsernameRequest from telethon.tl.types import InputChannel +from telethon.utils import get_extension +logging.basicConfig(level=logging.INFO) class BridgeBot: def __init__(self, cfg: dict): self.config = cfg - self.mastodon_client = Mastodon( - client_id=cfg["mastodon"]["client_id"], - client_secret=cfg["mastodon"]["client_secret"], - access_token=cfg["mastodon"]["access_token"], - api_base_url=cfg["mastodon"]["api_base_url"] - ) + self.mastodon_clients = {} + self.tg_mstdn_mappings = {} + for acc in cfg["mastodon"]["accounts"]: + mastodon_client = Mastodon( + client_id=acc["client_id"], + client_secret=acc["client_secret"], + access_token=acc["access_token"], + api_base_url=acc["api_base_url"] + ) + self.mastodon_clients[acc["name"]] = mastodon_client + + for m in cfg["mastodon"]["mappings"]: + if self.tg_mstdn_mappings.get("tg_channel_handle", None) is None: + self.tg_mstdn_mappings[m["tg_channel_handle"]] = [] + self.tg_mstdn_mappings[m["tg_channel_handle"]].append(m["account_name"]) + self.tg_client = TelegramClient(cfg["telegram"]["session_file"], cfg["telegram"]["api_id"], cfg["telegram"]["api_hash"]) @@ -33,6 +44,7 @@ class BridgeBot: channel = InputChannel(result.peer.channel_id, result.chats[0].access_hash) await self.tg_client(JoinChannelRequest(channel)) self.tg_client.add_event_handler(self._tg_event_handler) + logging.info("Bot has been started") await self.tg_client.run_until_disconnected() @events.register(events.NewMessage()) @@ -40,19 +52,34 @@ class BridgeBot: if event.message.post: channel = await event.get_chat() if channel.broadcast: - if channel.username in self.config["telegram"]["channels"]: - print("dobbry vechur") + if channel.username in self.tg_mstdn_mappings.keys(): + if event.message.grouped_id is not None: + logging.warning("Albums isn't supported yet") + return + logging.debug("dobbry vechur") + logging.info(f"Catched new post from telegram channel {channel.username}") text: str = event.message.text if event.message.forward: + logging.debug("The current post is forwarded") text = f"[from {event.message.forward.chat.title} (https://t.me/{event.message.forward.chat.username})]\n\n" + text - if event.message.photo: - temp_image_name = uuid.uuid4() - await self.tg_client.download_media(event.message.photo, f"/tmp/{temp_image_name}.jpg") - mstdn_media_meta = self.mastodon_client.media_post(f"/tmp/{temp_image_name}.jpg") - self.mastodon_client.status_post(text, media_ids=[mstdn_media_meta]) - os.remove(f"/tmp/{temp_image_name}.jpg") - return - self.mastodon_client.toot(text) + temp_file_path: str = "" + if (event.message.photo or event.message.video or event.message.gif) and not hasattr(event.message.media, "webpage"): + logging.debug("Post contains the media, downloading it...") + temp_file_name = uuid.uuid4() + temp_file_path = f"/tmp/{temp_file_name}{get_extension(event.message.media)}" + await self.tg_client.download_media(event.message.media, temp_file_path) + for mstdn_acc_name in self.tg_mstdn_mappings[channel.username]: + if self.mastodon_clients.get(mstdn_acc_name, None) is None: + logging.error(f"{mstdn_acc_name} doesn't exists in mastodon.accounts section of config!") + return + current_mastodon_client = self.mastodon_clients[mstdn_acc_name] + if temp_file_path != "": + mstdn_media_meta = current_mastodon_client.media_post(temp_file_path) + current_mastodon_client.status_post(text, media_ids=[mstdn_media_meta]) + else: + current_mastodon_client.toot(text) + if temp_file_path != "": + os.remove(temp_file_path) if __name__ == '__main__': @@ -62,6 +89,5 @@ if __name__ == '__main__': args = parser.parse_args() config: dict = toml.loads(open(args.config, "r").read()) - print(config) bot = BridgeBot(config) asyncio.get_event_loop().run_until_complete(bot.run()) diff --git a/sample.config.toml b/sample.config.toml index c1c141a..c614969 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -1,11 +1,26 @@ -[mastodon] -client_id = "abc" -client_secret = "def" -access_token = "ghi" -api_base_url = "mstdn.netwhood.online" +[[mastodon.mappings]] + account_name = "ChronosX" + tg_channel_handle = "ChronosX_Channel" + +[[mastodon.mappings]] + account_name = "floppy" + tg_channel_handle = "netwhood_news" + +[[mastodon.accounts]] + name = "ChronosX" + client_id = "abc" + client_secret = "def" + access_token = "ghi" + api_base_url = "mstdn.netwhood.online" + +[[mastodon.accounts]] + name = "floppy" + client_id = "abc" + client_secret = "def" + access_token = "ghi" + api_base_url = "mstdn.netwhood.online" [telegram] -api_id = "123123" -api_hash = "qwerty" -channels = [] # handles of channels without "@" -session_file = "/path/to/session/file" \ No newline at end of file + api_id = "123123" + api_hash = "qwerty" + session_file = "/path/to/session/file"