treehousehub-server/misskey_bridge.py
2025-05-24 09:14:19 -05:00

189 lines
7.0 KiB
Python

import misskey
import websockets
import json
import asyncio
import requests
from io import BytesIO
MISSKEY_INSTANCE = "misskey.treehousefullofstars.com"
MISSKEY_TOKEN = "JSvVuz1eS2BGq6MagdQC9m109gOllwcO"
msk = misskey.Misskey(address=MISSKEY_INSTANCE, i=MISSKEY_TOKEN)
MY_ID = msk.i()['id']
WS_URL=f"wss://{MISSKEY_INSTANCE}/streaming"
channels = ['localTimeline', 'globalTimeline' 'hybridTimeline', 'main']
discord_webhook = "https://discord.com/api/webhooks/1367836441098326107/fqDmUGd-u2sWXF9ymuAgArHPnmTCU70_pFaqagqFww9cd07ujjQ4S1s8KvVuc1O1xIHX"
async def handleMentions(message: str, mentions):
for mention in mentions:
user, discord = await getUserProfile(mention)
if user and discord:
misskey_mention_tag = f"@{user['username']}"
discord_mention_tag = f"<@{discord['user']['id']}>"
message = message.replace(misskey_mention_tag, discord_mention_tag)
return message
async def getUserProfile(userID):
api_endpoint = f"https://{MISSKEY_INSTANCE}/api/users/show"
bot_token = "MTMyNzcxNDM3MTEyMzgxMDMwNA.GwLjEd.quGP0FA5gHRe1xLyuYq-ANuJ5cRuRQ6dhJiojI"
guild_id = "954201387770736751"
params = {
"i": MISSKEY_TOKEN,
"userId": userID
}
response = requests.post(api_endpoint, json=params)
user_profile = None
discord_user = None
if response.status_code == 200:
user_profile = response.json()
else:
return user_profile, discord_user
discord_id = None
if user_profile != {}:
for field in user_profile.get('fields', []):
if field['name'] == "Discord":
discord_id = field['value']
discord_user = {}
if discord_id:
headers = {'Authorization': f'Bot {bot_token}'}
discord_guild_endpoint = f"https://discord.com/api/v10/guilds/{guild_id}/members/{discord_id}"
response = requests.get(discord_guild_endpoint, headers=headers)
if response.status_code == 200:
discord_user = response.json()
else:
return user_profile, discord_user
with open('user.json', 'w+') as file:
file.write(json.dumps({'user': user_profile, 'discord': discord_user}, indent=5))
return user_profile, discord_user
async def handle_message(websocket, message):
data = json.loads(message)
with open('test.json', 'w+') as file:
file.write(json.dumps(data, indent=5))
headers={
'Content-type':'application/json',
'Accept':'application/json'
}
response = requests.post("http://127.0.0.1:5000/misskey-connect", json=data, headers=headers)
print(response)
guild_id = "954201387770736751"
user_id = data['body']['body']['userId']
user, discord = await getUserProfile(userID=user_id)
with open('user.json', 'w+') as file:
file.write(json.dumps({'user': user, 'discord': discord}, indent=5))
if data['body']['type'] == "note":
print("note")
if data['body']['body']['renoteId']:
files = data['body']['body']['renote'].get('files', None)
else:
files = data['body']['body'].get('files', None)
passed_files = {}
if files != []:
for i, file in enumerate(files):
response = requests.get(file['url'])
file_data = BytesIO(response.content)
filename = file['name']
passed_files[f"file{i}"] = (filename, file_data, file['type'])
if data['body']['body']['renoteId']:
renote_user = data['body']['body']['renote']['user'].get('name', 'unknown')
renote_username = data['body']['body']['renote']['user'].get('username', 'unknown')
renote_user_host = data['body']['body']['renote']['user'].get('hose', 'unknown')
note_content = f"*Renoted {renote_user} (@{renote_username}@{renote_user_host})*\n{data['body']['body']['renote']['text']}"
else:
note_content = data['body']['body'].get('text', 'No text in note')
username = data['body']['body']['user'].get('name', 'Misskey Bot')
avatar_url = data['body']['body']['user'].get('avatarUrl', None)
if discord:
username = discord['nick']
if discord['avatar']:
avatar_url = f"https://cdn.discordapp.com/guilds/{guild_id}/users/{discord['user']['id']}/avatars/{discord['avatar']}.png"
else:
avatar_url = f"https://cdn.discordapp.com/avatars/{discord['user']['id']}/{discord['user']['avatar']}.png"
note_content = await handleMentions(note_content, data['body']['body'].get('mentions', []))
print(note_content, username, avatar_url)
if passed_files != {}:
await send_to_discord(note_content, username=username, avatar_url=avatar_url, files=passed_files)
else:
await send_to_discord(note_content, username=username, avatar_url=avatar_url)
async def send_to_discord(message, username="Misskey Bot", avatar_url=None, embeds=None, files=None):
content = f"{message}"
payload = {
"content": content,
"username": username,
"avatar_url": avatar_url
}
if embeds:
payload['embeds'] = embeds
print(payload)
if files:
response = requests.post(discord_webhook, data=payload, files=files)
else:
response = requests.post(discord_webhook, json=payload)
if response.status_code != 204:
print(f"Failed to send message to Discord: {response.status_code} {response.text}")
async def connect_and_listen():
while True:
try:
print("Connecting to WebSocket...")
async with websockets.connect(WS_URL) as websocket:
print("Connected to WebSocket")
# Subscribe to the channels
for channel in channels:
subscription_request = {
"type": "connect",
"body": {
"channel": channel,
"id": MY_ID,
"access_token": MISSKEY_TOKEN
}
}
await websocket.send(json.dumps(subscription_request))
print(f"Sent subscription request for {channel} channel with ID: {MY_ID}")
response = await websocket.recv()
print(f"Received response for {channel} channel: {response}")
await handle_message(websocket, response)
# Listen for messages
#while True:
# async for message in websocket:
# await handle_message(websocket, message)
except websockets.exceptions.ConnectionClosedError as e:
print(f"Connection closed unexpectedly: {e}")
await asyncio.sleep(5) # Wait for 5 seconds before retrying
except Exception as e:
print(f"An error occurred: {e}")
await asyncio.sleep(5) # Wait for 5 seconds before retrying
# Run the client
if __name__ == "__main__":
asyncio.run(connect_and_listen())