diff --git a/.gitignore b/.gitignore index 2ada06e..2ae6f12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -generate_images/2025-06-08 150855867880-gen-PNG-ujZRQA.png -generate_images/test-gen-image.png +generate_images/* + +__pycache__/* + diff --git a/assets/images/owncast.jpg b/assets/images/owncast.jpg new file mode 100644 index 0000000..a4dae1f Binary files /dev/null and b/assets/images/owncast.jpg differ diff --git a/bridges.py b/bridges.py index de912e0..61b74d1 100644 --- a/bridges.py +++ b/bridges.py @@ -31,7 +31,26 @@ def parse_links_from_mattermost(string): DISCORD_BOT_URL = 'http://localhost:5001/post_message' -def send_mattermost_to_discord(post, channel_to, avatar_url=None): +def getDiscordUserProfile(discord_user_id): + print("test") + bot_token = "MTMyNzcxNDM3MTEyMzgxMDMwNA.GwLjEd.quGP0FA5gHRe1xLyuYq-ANuJ5cRuRQ6dhJiojI" + guild_id = "954201387770736751" + headers = {'Authorization': f'Bot {bot_token}'} + discord_guild_endpoint = f"https://discord.com/api/v10/guilds/{guild_id}/members/{discord_user_id}" + response = requests.get(discord_guild_endpoint, headers=headers) + print(response) + if response.status_code == 200: + discord_user = response.json() + username = discord_user['nick'] + if discord_user['avatar']: + avatar_url = f"https://cdn.discordapp.com/guilds/{guild_id}/users/{discord_user['user']['id']}/avatars/{discord_user['avatar']}.png" + else: + avatar_url = f"https://cdn.discordapp.com/avatars/{discord_user['user']['id']}/{discord_user['user']['avatar']}.png" + return True, username, avatar_url + else: + return False, "Unknown", "" + +def send_mattermost_to_discord(post, webhook_url, avatar_url=""): post_message = parse_links_from_mattermost(post['message']) @@ -39,28 +58,17 @@ def send_mattermost_to_discord(post, channel_to, avatar_url=None): if post['user']['nickname'] == "": username = post['user']['username'] else: - username = post['user']['nickname'] + username = post['user']['nickname'] + + payload = { + "content": post_message, + "username": username, + "avatar_url": avatar_url + } - if avatar_url: - payload = { - "message": post_message, - "channel_to": channel_to, - "username": username, - "avatar_url": avatar_url, - "discord_id": post['discord_id'] - } - else: - payload = { - "message": post_message, - "channel_to": channel_to, - "username": username, - "avatar_url": None, - "discord_id": post['discord_id'] - } - - response = requests.post(DISCORD_BOT_URL, json=payload) - - if response.status_code == 200: + response = requests.post(webhook_url, data=payload) + print("webhook response: ", response) + if response.status_code == 204: print("Message sent successfully.") else: print("Failed to send the message.") @@ -82,34 +90,12 @@ def parse_links_from_discord(string): return string def send_discord_to_mattermost(message, channel_to): - bearer_token = "g9rpuzcpkpgyddozad6j5nui9r" - url = "http://chat.treehousefullofstars.com/api/v4/posts" - webhook_url = "https://chat.treehousefullofstars.com/hooks/qjxs466x1pr63y71bszze56x4c" - - channel_id = mattermostDriver.channels.get_channel_by_name_and_team_name('Treehousefullofstars', channel_to)['id'] - + channel_id = mattermostDriver.channels.get_channel_by_name_and_team_name(channel_to[1], channel_to[0])['id'] new_contents = "" count = 0 file_ids = [] - """if message.embeds: - print(message.embeds) - for embed in message.embeds: - new_contents += f"\n{embed.url}" - count += 1 - - file_url = embed.url - - response = requests.get(file_url) - file_data = response.content - - file_id = mattermostDriver.files.upload_file( - channel_id=channel_id, - files={'files': (embed.filename, file_data)} - )['file_infos'][0]['id'] - file_ids.append(file_id)""" if message.attachments: - print(message.attachments) for attachment in message.attachments: file_url = attachment.url @@ -122,17 +108,6 @@ def send_discord_to_mattermost(message, channel_to): )['file_infos'][0]['id'] file_ids.append(file_id) - - """payload = { - "channel": channel_to, - "text": message.content, - "username": message.author.nick, - "icon_url": message.author.display_avatar.url, - "file_ids": file_ids - } - response = requests.post(webhook_url, json=payload) - print(response.content)""" - text = message.content if count>0: text += new_contents @@ -186,4 +161,31 @@ def send_misskey_to_mattermost(event, channel_id): 'override_icon_url': avatar_url }, 'message': note_content, - 'file_ids': file_ids}) \ No newline at end of file + 'file_ids': file_ids}) + + +owncast_webhook = "https://chat.treehousefullofstars.com/hooks/3o9tozzipi8e3rtkcns63pesfr" +def send_owncast_to_mattermost(event): + print(event) + data = event['eventData'] + type = event['type'] + post = False + text = "" + + if type == "STREAM_STARTED": + text = f"Stream Starting... {data['streamTitle']}\n" + post = True + elif type == "STREAM_STOPPED": + text = f"Stream Stopping..." + post = True + elif type == "STREAM_TITLE_UPDATED": + text = f"Stream title changed! We are now streaming... {data['streamTitle']}" + post = True + + if post: + payload = { + "text": text, + "username": f"{data['name']} - Stream", + "icon_url": "http://192.168.1.67:8086/logo" + } + requests.post(owncast_webhook, json=payload) \ No newline at end of file diff --git a/discordapp.py b/discordapp.py index 1389df0..b81282e 100644 --- a/discordapp.py +++ b/discordapp.py @@ -70,13 +70,14 @@ async def on_ready(): channels = { - 1125968295967850559: "our-comforter", #comforter - 954201387770736754: "lounge", #lounge - 1119502004721557554: "town-square", # kweh - 1367978276185964584: "misskey", #misskey - 1167176429797113926: "photos-from-another-star", #photos-from-another-star - 1119508652844404816: "bulletin-board", #bulletin-board - 955394194766192690: "photos-of-the-gang" #photos-of-the-gang + 1125968295967850559: ("our-comforter", 'final-fantasy-14'), #comforter + 954201387770736754: ("lounge", 'final-fantasy-14'), #lounge + 1119502004721557554: ("town-square", 'Treehousefullofstars'), # kweh + 1367978276185964584: ("misskey", 'Treehousefullofstars'), #misskey + 1167176429797113926: ("photos-from-another-star", 'final-fantasy-14'), #photos-from-another-star + 1119508652844404816: ("bulletin-board", 'Treehousefullofstars'), #bulletin-board + 955394194766192690: ("photos-of-the-gang", 'final-fantasy-14'), #photos-of-the-gang + 1381391455574167653: ("stream", 'Treehousefullofstars'), } @client.event @@ -104,36 +105,6 @@ async def send_custom_message(channel: discord.TextChannel, message, username, u await webhook.send(message, username=username, avatar_url=avatar_url) await webhook.delete() -# flask -app = flask.Flask(__name__) - -@app.route('/post_message', methods=['POST']) -async def post_message(): - data:dict = flask.request.json - message = data.get('message') - username = data.get('username', 'Unknown') - avatar_url = data.get('avatar_url', None) - user_id = data.get('discord_id', None) - print(data) - if message == "": - return flask.jsonify({'error': 'Message cannot be blank.'}), 400 - - channel = client.get_channel(data['channel_to']) - if channel: - client.loop.create_task(send_custom_message(channel, message, username, user_id, avatar_url)) - #client.loop.create_task(channel.send(message)) - return flask.jsonify({'status': 'Message sent successfully.'}), 200 - else: - return flask.jsonify({'error': 'Channel not found.'}), 404 - -def run_flask_app(): - app.run(port=5001) - -# Run the Flask app in a separate thread -thread = Thread(target=run_flask_app) -thread.start() - - token = "MTMyNzcxNDM3MTEyMzgxMDMwNA.GwLjEd.quGP0FA5gHRe1xLyuYq-ANuJ5cRuRQ6dhJiojI" client.run(token) diff --git a/mattermost.app.py b/mattermost.app.py index f4da98c..939c2b4 100644 --- a/mattermost.app.py +++ b/mattermost.app.py @@ -3,15 +3,23 @@ from mattermostdriver import Driver import bridges channels = { - "ibfp3fskai8adgmynbfispz3se": 1125968295967850559, #comforter - "rb43iupdy7rjbjwhg9w9c1mzjy": 954201387770736754, # lounge - "s6muherhotfoircc1yzmwr5wty": 1119502004721557554, # kweh - "fkcqa3qj83gu3bfikcu55sfwww": 1367978276185964584, #misskey - "na4doo5f83ykbc45m9a5dn513a": 1167176429797113926, #photos-from-another-star - "9ydcz9orepbtmedncb7idh43hr": 1119508652844404816, #bulletin-board - "81qmzfzeeif7mmfhpy7hkxnjuc": 955394194766192690 #photos-of-the-gang + "zc69ns9jwpbn7c3wkxdf6x8nto": 1125968295967850559, #comforter + "ap61bgmm63f8irths1gk91zowh": 954201387770736754, # lounge + #"s6muherhotfoircc1yzmwr5wty": 1119502004721557554, # kweh + "fkcqa3qj83gu3bfikcu55sfwww": 1367978276185964584 #misskey + #"na4doo5f83ykbc45m9a5dn513a": 1167176429797113926, #photos-from-another-star + #"9ydcz9orepbtmedncb7idh43hr": 1119508652844404816, #bulletin-board + #"81qmzfzeeif7mmfhpy7hkxnjuc": 955394194766192690, #photos-of-the-gang + #"u1ffegpqj3gg7yephh6rnso74o": 1381391455574167653 #stream } +webhooks = { + 1125968295967850559: "https://discord.com/api/webhooks/1153490247905189909/pm_cDa8XqsTIlAsZY1uUFmSSvDZKjaI8u30mjFzmvHcMhMQFirQcWbI9rEee4OFmLNnu", + 954201387770736754: "https://discord.com/api/webhooks/1127805939425235029/c4RvvRDUfDuE0-cvTzlPQPYbaTN6UdZzEPfLypOQCGSejax93Gh99E3_xgbCirrh4CqH" +} + +post_webhooks_exemptions = ["u1ffegpqj3gg7yephh6rnso74o", "fkcqa3qj83gu3bfikcu55sfwww"] + users = { "f3nja8t9fpy73cxeh5ykzrozaw": 407247496008433675, "3byr3scix3f78xs5bpmgqzc6pc": 189202462442389514, @@ -36,23 +44,31 @@ async def event_handler(event): if is_webhook != "true": # add file syncing means you need to get the "file_ids" key from the post and then download them into blobs and pass those along # to the request as files, on the discord side those files would then get attached to the webhook. - + discord_channel_id = channels[post['channel_id']] + print(discord_channel_id) user = mattermostDriver.users.get_user(user_id=post['user_id']) #print(user) post['user'] = user discord_id = None print("user:", user) + avatar_url = "" if user['id'] in users.keys(): - discord_id = users[post['user']['id']] + discord_user_id = users[post['user']['id']] + status, username, avatar_url = bridges.getDiscordUserProfile(discord_user_id) + post['user']['nickname'] = username + print(avatar_url) + post['discord_id'] = discord_id - bridges.send_mattermost_to_discord(post, channel_to=channels[post['channel_id']]) - elif post['channel_id'] == "fkcqa3qj83gu3bfikcu55sfwww" and is_webhook == "true": + print(webhooks[discord_channel_id]) + bridges.send_mattermost_to_discord(post, webhook_url=webhooks[discord_channel_id], avatar_url=avatar_url) + elif post['channel_id'] in post_webhooks_exemptions and is_webhook == "true": + print("exempt channel!") username = post['props']['override_username'] avatar_url = post['props']['override_icon_url'] user = {"nickname": username} post['user'] = user post['discord_id'] = None - bridges.send_mattermost_to_discord(post, channel_to=channels[post['channel_id']], avatar_url=avatar_url) + bridges.send_mattermost_to_discord(post, webhook_url=webhooks[discord_channel_id], avatar_url=avatar_url) mattermostDriver = Driver({ "url": "192.168.1.67", diff --git a/owncast.app.py b/owncast.app.py new file mode 100644 index 0000000..ce58cf3 --- /dev/null +++ b/owncast.app.py @@ -0,0 +1,12 @@ +import flask +import bridges + +app = flask.Flask(__name__) + +@app.route('/owncast_webhook', methods=['POST']) +async def post_message(): + bridges.send_owncast_to_mattermost(flask.request.get_json()) + return flask.Response(status=200) + + +app.run(host="0.0.0.0", port=5002, debug=True) \ No newline at end of file diff --git a/test.json b/test.json index fe93c47..492d2d3 100644 --- a/test.json +++ b/test.json @@ -1,117 +1,20 @@ { - "type": "channel", - "body": { - "id": "a79jhleyz47f00j9", - "type": "note", - "body": { - "id": "a8qi6tndcsjw00uj", - "createdAt": "2025-06-08T00:42:51.673Z", - "userId": "a78vufh1z47f000t", - "user": { - "id": "a78vufh1z47f000t", - "name": "Gabriella Versi", - "username": "gabriella", - "host": null, - "avatarUrl": "https://misskey.treehousefullofstars.com/proxy/avatar.webp?url=https%3A%2F%2Fmisskey.treehousefullofstars.com%2Ffiles%2F64e5e5cf-5d64-40f1-91ab-f7858f4b0e18&avatar=1", - "avatarBlurhash": "eOPZ7PRjpd%Mx]_Nxt?bs:xZ%gWCROWCM|%gWBRjofWXSPf5xtt7V@", - "avatarDecorations": [], - "isBot": false, - "isCat": false, - "emojis": {}, - "onlineStatus": "online", - "badgeRoles": [ - { - "name": "Roots", - "iconUrl": null, - "displayOrder": 0 - } - ] - }, - "text": null, - "cw": null, - "visibility": "public", - "localOnly": false, - "reactionAcceptance": null, - "renoteCount": 0, - "repliesCount": 0, - "reactionCount": 0, - "reactions": {}, - "reactionEmojis": {}, - "reactionAndUserPairCache": [], - "fileIds": [], - "files": [], - "replyId": null, - "renoteId": "a8ohrbj431al069k", - "clippedCount": 0, - "renote": { - "id": "a8ohrbj431al069k", - "createdAt": "2025-06-06T14:55:16.000Z", - "userId": "a7xcts4vcsjw00at", - "user": { - "id": "a7xcts4vcsjw00at", - "name": "Information Is Beautiful", - "username": "infobeautiful", - "host": "vis.social", - "avatarUrl": "https://misskey.treehousefullofstars.com/proxy/avatar.webp?url=https%3A%2F%2Fcdn.masto.host%2Fvissocial%2Faccounts%2Favatars%2F111%2F030%2F299%2F829%2F248%2F466%2Foriginal%2F0d4bfae30dce0763.png&avatar=1", - "avatarBlurhash": "e2CY]zxI9xx@=y$%juXSa{aeD,ou~UV|bayCj@ena#t7yCRowIxo01", - "avatarDecorations": [], - "isBot": false, - "isCat": false, - "instance": { - "name": "vis.social", - "softwareName": "mastodon", - "softwareVersion": "4.3.8", - "iconUrl": "https://vis.social/packs/media/icons/android-chrome-36x36-4c61fdb42936428af85afdbf8c6a45a8.png", - "faviconUrl": "https://vis.social/packs/media/icons/favicon-48x48-c1197e9664ee6476d2715a1c4293bf61.png", - "themeColor": "#181820" - }, - "emojis": {}, - "onlineStatus": "unknown" - }, - "text": "Some interesting variations here...\n(by reddit user theworldmaps)", - "cw": null, - "visibility": "public", - "localOnly": false, - "reactionAcceptance": null, - "renoteCount": 1, - "repliesCount": 1, - "reactionCount": 0, - "reactions": {}, - "reactionEmojis": {}, - "reactionAndUserPairCache": [], - "emojis": {}, - "fileIds": [ - "a8ohrh7e31al069j" - ], - "files": [ - { - "id": "a8ohrh7e31al069j", - "createdAt": "2025-06-06T14:55:23.354Z", - "name": "b1743c8a716cf03a.png", - "type": "image/png", - "md5": "8fa3149c3db0e0d11e7b0b0007cabeeb", - "size": 0, - "isSensitive": false, - "blurhash": "eHQuZ@WdUE+^XoghOkXlw1oxLzNrmSr{t1vgQ;ogXOWZu2r;bwpaaM", - "properties": { - "width": 853, - "height": 1024 - }, - "url": "https://misskey.treehousefullofstars.com/files/webpublic-1225bfbb-9837-44b0-b0ac-1ed14fa1df92", - "thumbnailUrl": "https://misskey.treehousefullofstars.com/proxy/static.webp?url=https%3A%2F%2Fcdn.masto.host%2Fvissocial%2Fmedia_attachments%2Ffiles%2F114%2F636%2F994%2F245%2F080%2F080%2Foriginal%2Fb1743c8a716cf03a.png&static=1", - "comment": "A map of Europe showing the mean age of women at the birth of their first child, categorized by color from yellow (age 25) to purple (age 33). Examples include: Moldova with the youngest average age at 25.1, and Monaco with the highest at 32.5. Other notable countries: Spain at 31.6, Italy at 31.7, Germany at 29.9, and Finland at 29.9. The map includes small flags and labeled figures for precision. Data for the UK is from 2018, and other countries are from 2021 or 2022.", - "folderId": null, - "folder": null, - "userId": "a7xcts4vcsjw00at", - "user": null - } - ], - "replyId": null, - "renoteId": null, - "uri": "https://vis.social/users/infobeautiful/statuses/114636994393755424", - "url": "https://vis.social/@infobeautiful/114636994393755424", - "clippedCount": 0 - } - } - } + "eventData": { + "id": "YiLYhFLNRz", + "name": "Treehouse Full of Stars", + "status": { + "lastConnectTime": "2025-06-08T21:16:13Z", + "lastDisconnectTime": null, + "versionNumber": "0.2.3", + "streamTitle": "Messing around before Maps, test! tt", + "viewerCount": 0, + "overallMaxViewerCount": 5, + "sessionMaxViewerCount": 0, + "online": false + }, + "streamTitle": "Messing around before Maps, test! tt", + "summary": "", + "timestamp": "2025-06-08T21:16:13.781690442Z" + }, + "type": "STREAM_STARTED" } \ No newline at end of file