Implement configurable repost routing from TG to Mastodon

This commit is contained in:
ChronosX88 2020-08-30 15:11:50 +04:00
parent a6bc05844b
commit 27b0d78116
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
2 changed files with 71 additions and 30 deletions

View File

@ -1,27 +1,38 @@
import argparse
import asyncio import asyncio
import logging
import os import os
import uuid import uuid
from io import BytesIO
import toml import toml
import argparse
from mastodon import Mastodon from mastodon import Mastodon
from telethon import TelegramClient, events from telethon import TelegramClient, events
from telethon.events.common import EventBuilder from telethon.tl.functions.channels import JoinChannelRequest
from telethon.tl.functions.channels import JoinChannelRequest, GetMessagesRequest
from telethon.tl.functions.contacts import ResolveUsernameRequest from telethon.tl.functions.contacts import ResolveUsernameRequest
from telethon.tl.types import InputChannel from telethon.tl.types import InputChannel
from telethon.utils import get_extension
logging.basicConfig(level=logging.INFO)
class BridgeBot: class BridgeBot:
def __init__(self, cfg: dict): def __init__(self, cfg: dict):
self.config = cfg self.config = cfg
self.mastodon_client = Mastodon( self.mastodon_clients = {}
client_id=cfg["mastodon"]["client_id"], self.tg_mstdn_mappings = {}
client_secret=cfg["mastodon"]["client_secret"], for acc in cfg["mastodon"]["accounts"]:
access_token=cfg["mastodon"]["access_token"], mastodon_client = Mastodon(
api_base_url=cfg["mastodon"]["api_base_url"] 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"], self.tg_client = TelegramClient(cfg["telegram"]["session_file"], cfg["telegram"]["api_id"],
cfg["telegram"]["api_hash"]) cfg["telegram"]["api_hash"])
@ -33,6 +44,7 @@ class BridgeBot:
channel = InputChannel(result.peer.channel_id, result.chats[0].access_hash) channel = InputChannel(result.peer.channel_id, result.chats[0].access_hash)
await self.tg_client(JoinChannelRequest(channel)) await self.tg_client(JoinChannelRequest(channel))
self.tg_client.add_event_handler(self._tg_event_handler) self.tg_client.add_event_handler(self._tg_event_handler)
logging.info("Bot has been started")
await self.tg_client.run_until_disconnected() await self.tg_client.run_until_disconnected()
@events.register(events.NewMessage()) @events.register(events.NewMessage())
@ -40,19 +52,34 @@ class BridgeBot:
if event.message.post: if event.message.post:
channel = await event.get_chat() channel = await event.get_chat()
if channel.broadcast: if channel.broadcast:
if channel.username in self.config["telegram"]["channels"]: if channel.username in self.tg_mstdn_mappings.keys():
print("dobbry vechur") 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 text: str = event.message.text
if event.message.forward: 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 text = f"[from {event.message.forward.chat.title} (https://t.me/{event.message.forward.chat.username})]\n\n" + text
if event.message.photo: temp_file_path: str = ""
temp_image_name = uuid.uuid4() if (event.message.photo or event.message.video or event.message.gif) and not hasattr(event.message.media, "webpage"):
await self.tg_client.download_media(event.message.photo, f"/tmp/{temp_image_name}.jpg") logging.debug("Post contains the media, downloading it...")
mstdn_media_meta = self.mastodon_client.media_post(f"/tmp/{temp_image_name}.jpg") temp_file_name = uuid.uuid4()
self.mastodon_client.status_post(text, media_ids=[mstdn_media_meta]) temp_file_path = f"/tmp/{temp_file_name}{get_extension(event.message.media)}"
os.remove(f"/tmp/{temp_image_name}.jpg") 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 return
self.mastodon_client.toot(text) 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__': if __name__ == '__main__':
@ -62,6 +89,5 @@ if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()
config: dict = toml.loads(open(args.config, "r").read()) config: dict = toml.loads(open(args.config, "r").read())
print(config)
bot = BridgeBot(config) bot = BridgeBot(config)
asyncio.get_event_loop().run_until_complete(bot.run()) asyncio.get_event_loop().run_until_complete(bot.run())

View File

@ -1,4 +1,20 @@
[mastodon] [[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_id = "abc"
client_secret = "def" client_secret = "def"
access_token = "ghi" access_token = "ghi"
@ -7,5 +23,4 @@ api_base_url = "mstdn.netwhood.online"
[telegram] [telegram]
api_id = "123123" api_id = "123123"
api_hash = "qwerty" api_hash = "qwerty"
channels = [] # handles of channels without "@"
session_file = "/path/to/session/file" session_file = "/path/to/session/file"