Created and coded bridges between misskey,
mattermost, and discord
This commit is contained in:
parent
d8521a621b
commit
fea2efefc8
Binary file not shown.
Binary file not shown.
BIN
__pycache__/bridges.cpython-312.pyc
Normal file
BIN
__pycache__/bridges.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/discord.cpython-312.pyc
Normal file
BIN
__pycache__/discord.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/mattermost_bridge.cpython-312.pyc
Normal file
BIN
__pycache__/mattermost_bridge.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/mattermost_bridge.cpython-313.pyc
Normal file
BIN
__pycache__/mattermost_bridge.cpython-313.pyc
Normal file
Binary file not shown.
BIN
__pycache__/misskey.cpython-312.pyc
Normal file
BIN
__pycache__/misskey.cpython-312.pyc
Normal file
Binary file not shown.
189
bridges.py
Normal file
189
bridges.py
Normal file
@ -0,0 +1,189 @@
|
||||
import requests, re
|
||||
from mattermostdriver import Driver
|
||||
from bs4 import BeautifulSoup
|
||||
from io import BytesIO
|
||||
|
||||
mattermostDriver = Driver({
|
||||
"url": "192.168.1.67",
|
||||
"port": 8065,
|
||||
"scheme": "http",
|
||||
"token": "dmefeb8t7pditf3ot9377hrxch"
|
||||
})
|
||||
|
||||
mattermostDriver.login()
|
||||
|
||||
|
||||
def parse_links_from_mattermost(string):
|
||||
linkmatches = re.compile(r'\((https?://[^\s)]+)\)')
|
||||
fullmatches = re.compile(r'!\[.*?\]\(.*?\)')
|
||||
|
||||
links = linkmatches.findall(string)
|
||||
full = fullmatches.findall(string)
|
||||
|
||||
for match in full:
|
||||
string = string.replace(match, "")
|
||||
|
||||
for match in links:
|
||||
string += match
|
||||
|
||||
return string
|
||||
|
||||
|
||||
DISCORD_BOT_URL = 'http://localhost:5001/post_message'
|
||||
|
||||
def send_mattermost_to_discord(post, channel_to, avatar_url=None):
|
||||
|
||||
post_message = parse_links_from_mattermost(post['message'])
|
||||
|
||||
username = "Unknown"
|
||||
if post['user']['nickname'] == "":
|
||||
username = post['user']['username']
|
||||
else:
|
||||
username = post['user']['nickname']
|
||||
|
||||
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:
|
||||
print("Message sent successfully.")
|
||||
else:
|
||||
print("Failed to send the message.")
|
||||
print(response.text)
|
||||
|
||||
def parse_links_from_discord(string):
|
||||
linkmatches = re.compile(r'\bhttps?://(?:tenor|giphy)\.com/\S+\b')
|
||||
links = linkmatches.findall(string)
|
||||
|
||||
for match in links:
|
||||
response = requests.get(match)
|
||||
soup = BeautifulSoup(response.text, 'html.parser')
|
||||
gif_title = soup.find('meta', property='og:title')['content']
|
||||
gif_url = soup.find('meta', property='og:image')['content']
|
||||
|
||||
string = string.replace(match, "")
|
||||
string += f""
|
||||
|
||||
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']
|
||||
|
||||
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
|
||||
|
||||
response = requests.get(file_url)
|
||||
file_data = response.content
|
||||
|
||||
file_id = mattermostDriver.files.upload_file(
|
||||
channel_id=channel_id,
|
||||
files={'files': (attachment.filename, file_data)}
|
||||
)['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
|
||||
|
||||
text = parse_links_from_discord(text)
|
||||
|
||||
response = mattermostDriver.posts.create_post(options={
|
||||
'channel_id': channel_id,
|
||||
'props':{
|
||||
'from_webhook': 'true',
|
||||
'override_username': message.author.nick,
|
||||
'override_icon_url': message.author.display_avatar.url
|
||||
},
|
||||
'message': text,
|
||||
'file_ids': file_ids})
|
||||
|
||||
def send_misskey_to_mattermost(event, channel_id):
|
||||
if event['body']['body']['renoteId']:
|
||||
files = event['body']['body']['renote'].get('files', None)
|
||||
else:
|
||||
files = event['body']['body'].get('files', None)
|
||||
|
||||
file_ids=[]
|
||||
if files != []:
|
||||
for i, file in enumerate(files):
|
||||
response = requests.get(file['url'])
|
||||
file_data = BytesIO(response.content)
|
||||
filename = file['name']
|
||||
file_id = mattermostDriver.files.upload_file(
|
||||
channel_id=channel_id,
|
||||
files={'files': (filename, file_data)}
|
||||
)['file_infos'][0]['id']
|
||||
file_ids.append(file_id)
|
||||
|
||||
if event['body']['body']['renoteId']:
|
||||
renote_user = event['body']['body']['renote']['user'].get('name', 'unknown')
|
||||
renote_username = event['body']['body']['renote']['user'].get('username', 'unknown')
|
||||
renote_user_host = event['body']['body']['renote']['user'].get('hose', 'unknown')
|
||||
note_content = f"*Renoted {renote_user} (@{renote_username}@{renote_user_host})*\n{event['body']['body']['renote']['text']}"
|
||||
else:
|
||||
note_content = event['body']['body'].get('text', 'No text in note')
|
||||
|
||||
username = event['body']['body']['user'].get('name', 'Misskey Bot')
|
||||
avatar_url = event['body']['body']['user'].get('avatarUrl', '')
|
||||
|
||||
response = mattermostDriver.posts.create_post(options={
|
||||
'channel_id': channel_id,
|
||||
'props':{
|
||||
'from_webhook': 'true',
|
||||
'override_username':username,
|
||||
'override_icon_url': avatar_url
|
||||
},
|
||||
'message': note_content,
|
||||
'file_ids': file_ids})
|
||||
@ -1,8 +1,11 @@
|
||||
import discord
|
||||
from discord import app_commands
|
||||
#from discord import app_commands
|
||||
from NarratorAi import setScene, setItem, setRollDice
|
||||
import random
|
||||
|
||||
import flask
|
||||
import bridges
|
||||
from threading import Thread
|
||||
import requests
|
||||
|
||||
guild_id = 954201387770736751
|
||||
|
||||
@ -10,7 +13,9 @@ intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
|
||||
client = discord.Client(intents=intents)
|
||||
tree = app_commands.CommandTree(client)
|
||||
tree = discord.app_commands.CommandTree(client)
|
||||
|
||||
|
||||
|
||||
@tree.command(name="roll_die",
|
||||
description="Ask NARC to roll dice for you with flair.",
|
||||
@ -63,13 +68,73 @@ async def on_ready():
|
||||
await tree.sync(guild=discord.Object(id=guild_id))
|
||||
print(f'We have logged in as {client.user}')
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@client.event
|
||||
async def on_message(message):
|
||||
if message.author == client.user:
|
||||
return
|
||||
|
||||
if message.content.startswith('$hello'):
|
||||
await message.channel.send('Hello!')
|
||||
if not message.webhook_id and message.channel.id in channels.keys():
|
||||
bridges.send_discord_to_mattermost(message, channel_to=channels[message.channel.id])
|
||||
|
||||
|
||||
async def send_custom_message(channel: discord.TextChannel, message, username, user_id, avatar_url=None):
|
||||
if user_id:
|
||||
print(user_id)
|
||||
member = await channel.guild.fetch_member(user_id)
|
||||
avatar_url = member.display_avatar.url
|
||||
username = member.nick
|
||||
elif avatar_url:
|
||||
avatar_url = avatar_url
|
||||
else:
|
||||
avatar_url = ""
|
||||
|
||||
print(avatar_url)
|
||||
webhook = await channel.create_webhook(name=username)
|
||||
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)
|
||||
|
||||
|
||||
64
mattermost.app.py
Normal file
64
mattermost.app.py
Normal file
@ -0,0 +1,64 @@
|
||||
import requests, json
|
||||
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
|
||||
}
|
||||
|
||||
users = {
|
||||
"f3nja8t9fpy73cxeh5ykzrozaw": 407247496008433675,
|
||||
"3byr3scix3f78xs5bpmgqzc6pc": 189202462442389514
|
||||
}
|
||||
|
||||
async def event_handler(event):
|
||||
event = json.loads(event)
|
||||
if 'event' in event.keys() and event['event'] == "posted":
|
||||
print("event:", event)
|
||||
event_data = event['data']
|
||||
post = event_data['post']
|
||||
|
||||
post = json.loads(post)
|
||||
if post['channel_id'] in channels.keys():
|
||||
print(f"watched channel {post['channel_id']}")
|
||||
if 'from_webhook' in post['props'].keys():
|
||||
is_webhook = post['props']['from_webhook']
|
||||
else:
|
||||
is_webhook = "false"
|
||||
print(is_webhook)
|
||||
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.
|
||||
|
||||
user = mattermostDriver.users.get_user(user_id=post['user_id'])
|
||||
#print(user)
|
||||
post['user'] = user
|
||||
discord_id = None
|
||||
print("user:", user)
|
||||
if user['id'] in users.keys():
|
||||
discord_id = users[post['user']['id']]
|
||||
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":
|
||||
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)
|
||||
|
||||
mattermostDriver = Driver({
|
||||
"url": "192.168.1.67",
|
||||
"port": 8065,
|
||||
"scheme": "http",
|
||||
"token": "dmefeb8t7pditf3ot9377hrxch"
|
||||
})
|
||||
|
||||
mattermostDriver.login()
|
||||
mattermostDriver.init_websocket(event_handler)
|
||||
59
misskey.app.py
Normal file
59
misskey.app.py
Normal file
@ -0,0 +1,59 @@
|
||||
import asyncio
|
||||
import websockets
|
||||
import misskey
|
||||
import json
|
||||
import requests
|
||||
from io import BytesIO
|
||||
import bridges
|
||||
|
||||
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']
|
||||
|
||||
|
||||
async def event_handler(event):
|
||||
event = json.loads(event)
|
||||
if event['body']['type'] == "note":
|
||||
bridges.send_misskey_to_mattermost(event, "fkcqa3qj83gu3bfikcu55sfwww")
|
||||
|
||||
|
||||
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 event_handler(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
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(connect_and_listen())
|
||||
117
test.json
Normal file
117
test.json
Normal file
@ -0,0 +1,117 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
test.py
Normal file
25
test.py
Normal file
@ -0,0 +1,25 @@
|
||||
import re
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
# pattern = re.compile(r'!\[.*?\]\(.*?\)')
|
||||
#pattern = re.compile(r'!\[.*?\]\(.*?\)')
|
||||
linkmatches = re.compile(r'\b(?:https?://|www\.)\S+\b')
|
||||
|
||||
test_string = "https://tenor.com/view/i-love-you-iloveyou-i-love-it-love-you-love-u-gif-1804813945664624577"
|
||||
|
||||
|
||||
links = linkmatches.findall(test_string)
|
||||
|
||||
|
||||
for match in links:
|
||||
|
||||
response = requests.get(match)
|
||||
soup = BeautifulSoup(response.text, 'html.parser')
|
||||
gif_title = soup.find('meta', property='og:title')['content']
|
||||
gif_url = soup.find('meta', property='og:image')['content']
|
||||
|
||||
test_string = test_string.replace(match, "")
|
||||
test_string += f""
|
||||
|
||||
print(test_string)
|
||||
Loading…
x
Reference in New Issue
Block a user