commit 2b1b986dd254ad72977c692d845e13fc35cdc091 Author: laoxong Date: Sat Nov 20 17:59:54 2021 +0800 TG to Misskey diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d015b3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/credentials.py +/tmp_img diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..081b737 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 数据源本地存储已忽略文件 +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/Fediverse-Bridge.iml b/.idea/Fediverse-Bridge.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/Fediverse-Bridge.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..a5f943b --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a6fa933 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fce6de9 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f954e18 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +Fediverse-Bridge 项目主要目的是从其他地方自动转发至Misskey + +代码参(抄)考(袭): +[cyborg-ubyvtsya/telegram-mastodon-bridge](https://github.com/cyborg-ubyvtsya/telegram-mastodon-bridge) + +[ybw2016v/bilibili2notes](https://github.com/ybw2016v/bilibili2notes) + +原README.md +
+ cyborg-ubyvtsya/telegram-mastodon-bridge Readme.md + # Telebridge + +![demonstration](https://github.com/cyborg-ubyvtsya/telegram-mastodon-bridge/blob/main/img/demo.gif) + +Telegram/Mastodon bot for forwarding messages. + +## Usage + +- [Create a telegram bot](https://core.telegram.org/bots#3-how-do-i-create-a-bot) +- - Recieve telegram's access token +- [Create a mastodon bot](https://tinysubversions.com/notes/mastodon-bot/) +- - Give it the rights to write statuses +- - Save mastodon's access token +- Subscribe your telegram bot to channel(s) you need +- Install dependencies `pip install -r requirements.txt` +- Launch main.py and follow instructions +- Bot will start forwarding posts + +### Limitations + +- Only reposts plain text, images, and videos +- Image galleries are published as separate posts + +# Телеміст + +Телеграм/Мастодон бот, який дописи з тг в мастодон. + +## Використання + +- [Створіть бота в Телеграм](https://core.telegram.org/bots#3-how-do-i-create-a-bot) +- - Отримайте токен доступу +- [Створіть бота в Мастодон](https://tinysubversions.com/notes/mastodon-bot/) +- - Дайте йому доступ до створення дописів +- - Збережіть токен доступу +- Підпишіть бота на потрібні канали в телеграмі +- Встановіть залежності `pip install -r requirements.txt` +- Відкрийте main.py і змініть видимість постів в `mastodon_visibility = "direct"` +- Запустіть скрипт і слідуйте інструкціям +- Бот почне постити нові дописи з каналу на який він підписаний + +### Обмеження + +- Підтримуються лише текст, світлини, та відео +- Галереї публікуються в окремих дописах + +
diff --git a/__pycache__/credentials.cpython-39.pyc b/__pycache__/credentials.cpython-39.pyc new file mode 100644 index 0000000..c6b9a01 Binary files /dev/null and b/__pycache__/credentials.cpython-39.pyc differ diff --git a/main.py b/main.py new file mode 100755 index 0000000..1368bc1 --- /dev/null +++ b/main.py @@ -0,0 +1,273 @@ +#!/bin/env python +''' +|--------------------------------------------------------------| +| Telegram to Mastodon bridge | +|--------------------------------------------------------------| + +Telegram bot API documentation: + https://pypi.org/project/pyTelegramBotAPI/ +Mastodon bot API documentation: + https://mastodonpy.readthedocs.io/en/stable/ + +''' +import os +import logging +import time +import telebot +from mastodon import Mastodon +import requests +import json + + + + +''' +Basic setup +''' +logging.basicConfig(format='%(asctime)s: %(levelname)s %(name)s | %(message)s', + level=logging.INFO) +logger = telebot.logger.setLevel(logging.INFO) + +# check if credentials exist, create if not +if not os.path.isfile("credentials.py"): + logging.info("No credentials found") + telegram_token = input("输入你的telegram bot token: ") + web_type=input("输入网站类型(misskey):") + if web_type == 'misskey': + misskey_token = input("请输入Misskey bot token:") + misskey_instance = input("请输入Misskey实例地址:") + misskey_visibility = input("帖子类型(public,home,followers)") + character_limit = input("字数限制:") + with open("credentials.py", "w") as creds: + creds.write(f"telegram_token = '{telegram_token}'\nmisskey_token = '{misskey_token}'\nweb_type= '{web_type}'\nmisskey_instance = '{misskey_instance}'\nmisskey_visibility='{misskey_visibility}'\ncharacter_limit={character_limit}") + elif web_type == "mastodon": + character_limit = 500 + mastodon_token = input("输入你的mastodon bot token: ") + mastodon_instance = input( + "输入mastodon实例地址(https://example.social): ") + web = mastodon_instance + mastodon_visibility = input( + "输入mastodon嘟文类型(public, unlisted, or private): ") + with open("credentials.py", "w") as creds: + creds.write(f"telegram_token = '{telegram_token}'\nweb_type= '{web_type}'\nmastodon_token = '{mastodon_token}'\nmastodon_instance = '{mastodon_instance}'\nmastodon_visibility={mastodon_visibility}") + else: + print("输入有误") + +else: + try: + from credentials import * + logging.info("Running normally") + except ImportError: + logging.fatal( + "Something is wrong with credentials, delete credentials.py and try again") + exit(1) + +''' +Bots +''' +# Mastodon +if web_type == "mastodon": + mastodon_bot = Mastodon(access_token=mastodon_token, + api_base_url=mastodon_instance) # i.e.https://mastodon.social + +# Telegram +# parse mode can be either HTML or MARKDOWN +bot = telebot.TeleBot(telegram_token, parse_mode="HTML") + + +def ping_bots(): + if web_type == "mastodon": + try: + ping_mastodon = mastodon_bot.me()["username"] + logging.info(f"Running mastodon as {ping_mastodon}") + except: + logging.fatal("Failed to verify mastodon access token.") + exit(1) + + try: + a = requests.get('https://api.telegram.org/') + if a.status_code != 200: + logging.info(f"无法连接至TG API服务器") + ping_telegram = bot.get_me() + logging.info(f"Running telegram as {ping_telegram.username}") + except: + logging.fatal("Failed to verify telegram token.") + exit(1) + + +''' +Functions +''' +def ping_web(): + webget = requests.get(web) + if webget.status_code != 200: + print("实例连接错误") + exit(1) + +def footer_text(message): + if message.forward_from_chat != None and message.chat.username != None: + final_text = message.text + "\r\rFrom " + message.chat.username + \ + f"\nForwarded from {message.forward_from_chat.title}" + elif message.forward_from_chat != None and message.chat.username == None: + final_text = message.text + "\r\r" + message.chat.title + \ + f"\nForwarded from {message.forward_from_chat.title}" + elif message.chat.username != None: + final_text = message.text + "\r\rFrom " + message.chat.username + elif message.chat.username == None: + final_text = message.text + "\r\r" + message.chat.title + else: + final_text = message.text + + if len(final_text) < character_limit: + return final_text + else: + pass + + +def footer_image(message): + if message.forward_from_chat != None: + forward = f"\n转发自 {message.forward_from_chat.title}" + try: + caption = message.json['caption'] + if message.chat.username != None: + final_text = caption + "\r\r来自 " + message.chat.username + forward + return final_text + else: + final_text = caption + "\r\r" + message.chat.title + forward + return final_text + except: + if message.chat.username != None: + final_text = "来自 " + message.chat.username + forward + return final_text + else: + final_text = message.chat.title + forward + return final_text + else: + try: + caption = message.json['caption'] + if message.chat.username != None: + final_text = caption + "\r\r来自 " + message.chat.username + return final_text + else: + final_text = caption + "\r\r" + message.chat.title + return final_text + except KeyError: + if message.chat.username != None: + final_text = "来自 " + message.chat.username + return final_text + else: + final_text = message.chat.title + return final_text + + +''' +#Posting +''' + +''' +#mastodon 有空写 +@bot.channel_post_handler(content_types=["photo"]) +def get_image(message): + logging.info(f"New {message.content_type}") + caption = footer_image(message) + + fileID = message.photo[-1].file_id + logging.info(f"Photo ID {fileID}") + + file_info = bot.get_file(fileID) + downloaded_file = bot.download_file(file_info.file_path) + with open("tmp_img", "wb") as tmp_image: + tmp_image.write(downloaded_file) + + media_id = mastodon_bot.media_post("tmp_img") + posted = mastodon_bot.status_post( + status=caption, media_ids=media_id, visibility=mastodon_visibility) + logging.info(f"Posted: {posted['uri']}") + + +@bot.channel_post_handler(content_types=["video"]) +def get_video(message): + logging.info(f"New {message.content_type}") + caption = footer_image(message) + + fileID = message.video.file_id + logging.info(f"Video ID {fileID}") + + file_info = bot.get_file(fileID) + downloaded_file = bot.download_file(file_info.file_path) + with open("tmp_video", "wb") as tmp_video: + tmp_video.write(downloaded_file) + + media_id = mastodon_bot.media_post( + "tmp_video", mime_type=message.video.mime_type) + posted = mastodon_bot.status_post( + status=caption, media_ids=media_id, visibility=mastodon_visibility) + logging.info(f"Posted: {posted['uri']}") + + +# repost text messages +@bot.channel_post_handler(content_types=["text"]) +def get_text(message): + logging.info(f"New {message.content_type}") + status_text = footer_text(message) + + if type(status_text) == list: + recent_post = mastodon_bot.status_post( + status=status_text[0], visibility=mastodon_visibility) + + for i in status_text[1:]: + time.sleep(1) + this_recent_post = mastodon_bot.status_post( + status=i, visibility=mastodon_visibility, in_reply_to_id=recent_post.get('id')) + recent_post = this_recent_post + else: + print(status_text) + mastodon_bot.status_post( + status=status_text, visibility=mastodon_visibility) +''' + + +#Misskey + +@bot.channel_post_handler(content_types=["text"]) +def get_text(message): + logging.info(f"New {message.content_type}") + status_text = footer_text(message) + rjson = {'text': status_text, "localOnly": False, "visibility": misskey_visibility, "viaMobile": False, "i": misskey_token} + notepost = requests.post(misskey_instance + "/api/notes/create", json=rjson) + +@bot.channel_post_handler(content_types=["photo"]) +def get_image(message): + logging.info(f"New {message.content_type}") + caption = footer_image(message) + + fileID = message.photo[-1].file_id + logging.info(f"Photo ID {fileID}") + + file_info = bot.get_file(fileID) + downloaded_file = bot.download_file(file_info.file_path) + with open("tmp_img", "wb") as tmp_image: + tmp_image.write(downloaded_file) + rmediajson = {"i": misskey_token} + files = {'file': ("tmp_img",open("tmp_img", "rb"),'image/png')} + mediapost = requests.post(misskey_instance+'/api/drive/files/create', data=rmediajson, files=files) + media_id_list=[] + media_id_list.append(json.loads(mediapost.text)["id"]) + rjson = {'text': caption, "localOnly": False, "visibility": misskey_visibility, "fileIds":media_id_list, "viaMobile": False, "i": misskey_token} + posted = requests.post(misskey_instance + "/api/notes/create", json=rjson) + +''' +Finally run tg polling +''' + +try: + ping_bots() + bot.polling(interval=5) +except KeyboardInterrupt: + exit(0) +except: + logging.error("Something went wrong.") + ping_bots() + bot.polling(interval=5) +finally: + print("\nBye!") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5746a2a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Mastodon.py +pyTelegramBotAPI +requests