From c3d275e28d31a24860755940fef8817994143c28 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sat, 11 Nov 2023 17:33:34 +0000 Subject: [PATCH 01/11] Add support for TikTok (vxtiktok) embedding. Formatted with Black --- snsconverter/commandHandlers.py | 4 +- snsconverter/constants.py | 2 + snsconverter/eventHandlers.py | 3 +- snsconverter/eventsCore.py | 94 ++++++++++++++++++++++++++++++--- snsconverter/helpers.py | 25 ++++++++- snsconverter/snsconverter.py | 2 +- 6 files changed, 119 insertions(+), 11 deletions(-) diff --git a/snsconverter/commandHandlers.py b/snsconverter/commandHandlers.py index b0f68797..fee53f02 100644 --- a/snsconverter/commandHandlers.py +++ b/snsconverter/commandHandlers.py @@ -14,7 +14,7 @@ async def _grpSns(self, ctx: Context): async def _cmdToggle(self, ctx: Context): """Toggle SNSConverter replacements on the server - This will toggle the auto-reply of any Twitter or Instagram links with - embeds, and replace them with vxtwitter or ddinstagram, respectively. + This will toggle the auto-reply of any Twitter, Instagram or Tiktok links with + embeds, and replace them with vxtwitter, ddinstagram or vxtiktok, respectively. """ await self.cmdToggle(ctx) diff --git a/snsconverter/constants.py b/snsconverter/constants.py index 82c5baf0..f115a2a3 100644 --- a/snsconverter/constants.py +++ b/snsconverter/constants.py @@ -4,8 +4,10 @@ KEY_ENABLED = "enabled" DEFAULT_GUILD = {KEY_ENABLED: False} INSTA_REGEX_PATTERN = re.compile(r"https://(?:www\.)?(instagram.com)") +TIKTOK_REGEX_PATTERN = re.compile(r"https://(www\.|vm\.)?(tiktok.com)") class SocialMedia(enum.Enum): INSTAGRAM = "Instagram" TWITTER = "Twitter" + TIKTOK = "TikTok" diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index 84a2e096..048e7bbd 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -1,5 +1,4 @@ from discord import Message - from redbot.core import commands from .eventsCore import EventsCore @@ -10,8 +9,10 @@ class EventHandlers(EventsCore): async def twit_replacer(self, message: Message): await self._on_message_twit_replacer(message) await self._on_message_insta_replacer(message) + await self._on_message_tik_replacer(message) @commands.Cog.listener("on_message_edit") async def twit_edit_replacer(self, message_before: Message, message_after): await self._on_edit_twit_replacer(message_before, message_after) await self._on_edit_insta_replacer(message_before, message_after) + await self._on_edit_tik_replacer(message_before, message_after) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 5463002b..43595d16 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -2,7 +2,13 @@ from .constants import KEY_ENABLED, SocialMedia from .core import Core -from .helpers import convert_to_ddinsta_url, convert_to_vx_twitter_url, urls_to_string, valid +from .helpers import ( + convert_to_ddinsta_url, + convert_to_vx_tiktok_url, + convert_to_vx_twitter_url, + urls_to_string, + valid, +) class EventsCore(Core): @@ -30,7 +36,9 @@ async def _on_message_insta_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_insta_replacer(self, message_before: Message, message_after: Message): + async def _on_edit_insta_replacer( + self, message_before: Message, message_after: Message + ): if not valid(message_after): return @@ -43,7 +51,9 @@ async def _on_edit_insta_replacer(self, message_before: Message, message_after: return new_embeds = [ - embed for embed in message_after.embeds if embed not in message_before.embeds + embed + for embed in message_after.embeds + if embed not in message_before.embeds ] # skips if the message has no new embeds @@ -56,7 +66,9 @@ async def _on_edit_insta_replacer(self, message_before: Message, message_after: return # constructs the message and replies with a mention - ok = await message_after.reply(urls_to_string(ddinsta_urls, SocialMedia.INSTAGRAM)) + ok = await message_after.reply( + urls_to_string(ddinsta_urls, SocialMedia.INSTAGRAM) + ) # Remove embeds from user message if reply is successful if ok: @@ -88,7 +100,9 @@ async def _on_message_twit_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_twit_replacer(self, message_before: Message, message_after: Message): + async def _on_edit_twit_replacer( + self, message_before: Message, message_after: Message + ): # skips if the message is sent by any bot if not valid(message_after): return @@ -118,7 +132,75 @@ async def _on_edit_twit_replacer(self, message_before: Message, message_after: M return # constructs the message and replies with a mention - ok = await message_after.reply(urls_to_string(vx_twtter_urls, SocialMedia.TWITTER)) + ok = await message_after.reply( + urls_to_string(vx_twtter_urls, SocialMedia.TWITTER) + ) + + # Remove embeds from user message if reply is successful + if ok: + await message_after.edit(suppress=True) + + async def _on_message_tik_replacer(self, message: Message): + if not valid(message): + return + + if not await self.config.guild(message.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message.guild.name, + message.guild.id, + ) + return + + # the actual code part + vx_tiktok_urls = convert_to_vx_tiktok_url(message.embeds) + + # no changed urls detected + if not vx_tiktok_urls: + return + + # constructs the message and replies with a mention + ok = await message.reply(urls_to_string(vx_tiktok_urls, SocialMedia.TIKTOK)) + + # Remove embeds from user message if reply is successful + if ok: + await message.edit(suppress=True) + + async def _on_edit_tik_replacer( + self, message_before: Message, message_after: Message + ): + # skips if the message is sent by any bot + if not valid(message_after): + return + + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message_after.guild.name, + message_after.guild.id, + ) + return + + video_embed_before = [embed for embed in message_before.embeds if embed.video] + video_embed_after = [embed for embed in message_after.embeds if embed.video] + new_video_embeds = [ + embed for embed in video_embed_after if embed not in video_embed_before + ] + + # skips if the message has no new embeds + if not new_video_embeds: + return + + vx_tiktok_urls = convert_to_vx_tiktok_url(new_video_embeds) + + # no changed urls detected + if not vx_tiktok_urls: + return + + # constructs the message and replies with a mention + ok = await message_after.reply( + urls_to_string(vx_tiktok_urls, SocialMedia.TIKTOK) + ) # Remove embeds from user message if reply is successful if ok: diff --git a/snsconverter/helpers.py b/snsconverter/helpers.py index e5fc444d..762dbd32 100644 --- a/snsconverter/helpers.py +++ b/snsconverter/helpers.py @@ -2,7 +2,7 @@ from discord import Embed, Message, channel -from .constants import INSTA_REGEX_PATTERN, SocialMedia +from .constants import INSTA_REGEX_PATTERN, TIKTOK_REGEX_PATTERN, SocialMedia def convert_to_ddinsta_url(embeds: list[Embed]): @@ -28,6 +28,29 @@ def convert_to_ddinsta_url(embeds: list[Embed]): return ddinsta_urls +def convert_to_vx_tiktok_url(embeds: list[Embed]): + """ + Parameters + ---------- + embeds: list of Discord embeds + + Returns + ------- + filtered list of TikTok URLs that have been converted to vxtiktok + """ + + # pulls only video embeds from list of embeds + urls = [entry.url for entry in embeds] + + vxtiktok_urls = [ + re.sub(TIKTOK_REGEX_PATTERN, r"https://\1vx\2", result) + for result in urls + if re.match(TIKTOK_REGEX_PATTERN, result) + ] + + return vxtiktok_urls + + def convert_to_vx_twitter_url(embeds: list[Embed]): """ Parameters diff --git a/snsconverter/snsconverter.py b/snsconverter/snsconverter.py index 3fda992f..e93cdc60 100644 --- a/snsconverter/snsconverter.py +++ b/snsconverter/snsconverter.py @@ -5,6 +5,6 @@ class SNSConverter(commands.Cog, CommandHandlers, EventHandlers): - """Converts Twitter link to SNSConverter for better video embeds""" + """Converts Twitter, Instagram & Tiktok links for better video embeds""" pass From dde88546bc13c0771b099f09b4f3fd9a473ff29b Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sat, 11 Nov 2023 19:06:38 +0000 Subject: [PATCH 02/11] Twitter no longer embeds, and it's called "x" Add fxtwitter/fixupx link conversion --- snsconverter/constants.py | 3 +++ snsconverter/eventsCore.py | 34 +++++++--------------------------- snsconverter/helpers.py | 37 +++++++++++++++++++++++++------------ 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/snsconverter/constants.py b/snsconverter/constants.py index f115a2a3..3e1797bc 100644 --- a/snsconverter/constants.py +++ b/snsconverter/constants.py @@ -5,9 +5,12 @@ DEFAULT_GUILD = {KEY_ENABLED: False} INSTA_REGEX_PATTERN = re.compile(r"https://(?:www\.)?(instagram.com)") TIKTOK_REGEX_PATTERN = re.compile(r"https://(www\.|vm\.)?(tiktok.com)") +TWITTER_REGEX_PATTERN = re.compile(r"https://(?:www\.|)twitter\.com(/[^/]+/status/\d+)") +X_REGEX_PATTERN = re.compile(r"https://(?:www\.|)x\.com(/[^/]+/status/\d+)") class SocialMedia(enum.Enum): INSTAGRAM = "Instagram" + # I'm not calling it f****ng "x" lol TWITTER = "Twitter" TIKTOK = "TikTok" diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 43595d16..5f235602 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -4,8 +4,8 @@ from .core import Core from .helpers import ( convert_to_ddinsta_url, + convert_to_fx_twitter_url, convert_to_vx_tiktok_url, - convert_to_vx_twitter_url, urls_to_string, valid, ) @@ -87,18 +87,14 @@ async def _on_message_twit_replacer(self, message: Message): return # the actual code part - vx_twtter_urls = convert_to_vx_twitter_url(message.embeds) + fx_twtter_urls = convert_to_fx_twitter_url(message.content) # no changed urls detected - if not vx_twtter_urls: + if not fx_twtter_urls: return # constructs the message and replies with a mention - ok = await message.reply(urls_to_string(vx_twtter_urls, SocialMedia.TWITTER)) - - # Remove embeds from user message if reply is successful - if ok: - await message.edit(suppress=True) + await message.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) async def _on_edit_twit_replacer( self, message_before: Message, message_after: Message @@ -115,30 +111,14 @@ async def _on_edit_twit_replacer( ) return - video_embed_before = [embed for embed in message_before.embeds if embed.video] - video_embed_after = [embed for embed in message_after.embeds if embed.video] - new_video_embeds = [ - embed for embed in video_embed_after if embed not in video_embed_before - ] - - # skips if the message has no new embeds - if not new_video_embeds: - return - - vx_twtter_urls = convert_to_vx_twitter_url(new_video_embeds) + fx_twtter_urls = convert_to_fx_twitter_url(message_after.content) # no changed urls detected - if not vx_twtter_urls: + if not fx_twtter_urls: return # constructs the message and replies with a mention - ok = await message_after.reply( - urls_to_string(vx_twtter_urls, SocialMedia.TWITTER) - ) - - # Remove embeds from user message if reply is successful - if ok: - await message_after.edit(suppress=True) + await message_after.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) async def _on_message_tik_replacer(self, message: Message): if not valid(message): diff --git a/snsconverter/helpers.py b/snsconverter/helpers.py index 762dbd32..6f55fc57 100644 --- a/snsconverter/helpers.py +++ b/snsconverter/helpers.py @@ -2,7 +2,13 @@ from discord import Embed, Message, channel -from .constants import INSTA_REGEX_PATTERN, TIKTOK_REGEX_PATTERN, SocialMedia +from .constants import ( + INSTA_REGEX_PATTERN, + TIKTOK_REGEX_PATTERN, + TWITTER_REGEX_PATTERN, + X_REGEX_PATTERN, + SocialMedia, +) def convert_to_ddinsta_url(embeds: list[Embed]): @@ -51,27 +57,34 @@ def convert_to_vx_tiktok_url(embeds: list[Embed]): return vxtiktok_urls -def convert_to_vx_twitter_url(embeds: list[Embed]): +def convert_to_fx_twitter_url(message_content: str): """ Parameters ---------- - embeds: list of Discord embeds + message_content: str Returns ------- - filtered list of twitter URLs that have been converted to vxtwitter + filtered list of twitter/x URLs that have been converted to fxtwitter/fixupx """ - # pulls only video embeds from list of embeds - urls = [entry.url for entry in embeds if entry.video] + message_split = message_content.split() - vxtwitter_urls = [ - result.replace("https://twitter.com", "https://vxtwitter.com") - for result in urls - if "https://twitter.com" in result - ] + fixed_urls = [] + + # Extracts all twitter urls from message content, and converts them to fxtwitter, returning a list of urls + for word in message_split: + # I don't think @everyone will work anyway, but just incase... + if "@" in word: + continue + elif re.match(TWITTER_REGEX_PATTERN, word): + fixed_urls.append( + re.sub(TWITTER_REGEX_PATTERN, r"https://fxtwitter.com\1", word) + ) + elif re.match(X_REGEX_PATTERN, word): + fixed_urls.append(re.sub(X_REGEX_PATTERN, r"https://fixupx.com\1", word)) - return vxtwitter_urls + return fixed_urls def urls_to_string(links: list[str], socialMedia: SocialMedia): From 2887024d752961ea32b031291e28630fa79b8a03 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 00:13:06 +0000 Subject: [PATCH 03/11] Twitter doesn't embed at all, update logic --- snsconverter/eventsCore.py | 15 +++++++++++++++ snsconverter/helpers.py | 7 +------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 5f235602..5c6b2404 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -16,6 +16,10 @@ async def _on_message_insta_replacer(self, message: Message): if not valid(message): return + # skips if the message has no embeds + if not message.embeds: + return + if not await self.config.guild(message.guild).get_attr(KEY_ENABLED)(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", @@ -42,6 +46,10 @@ async def _on_edit_insta_replacer( if not valid(message_after): return + # skips if the message has no embeds + if not message_after.embeds: + return + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", @@ -124,6 +132,9 @@ async def _on_message_tik_replacer(self, message: Message): if not valid(message): return + if not message.embeds: + return + if not await self.config.guild(message.guild).get_attr(KEY_ENABLED)(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", @@ -153,6 +164,10 @@ async def _on_edit_tik_replacer( if not valid(message_after): return + # skips if the message has no embeds + if not message_after.embeds: + return + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", diff --git a/snsconverter/helpers.py b/snsconverter/helpers.py index 6f55fc57..44d01396 100644 --- a/snsconverter/helpers.py +++ b/snsconverter/helpers.py @@ -118,7 +118,7 @@ def valid(message: Message): Returns ------- - True if the message is from a human in a guild and contains embeds + True if the message is from a human in a guild False otherwise """ @@ -129,9 +129,4 @@ def valid(message: Message): # skips if message is in dm if isinstance(message.channel, channel.DMChannel): return False - - # skips if the message has no embeds - if not message.embeds: - return False - return True From c134417e92038baf882ba2c626491e8fc54fe7d9 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 00:14:52 +0000 Subject: [PATCH 04/11] uwu message doesn't make sense for twitter --- snsconverter/helpers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/snsconverter/helpers.py b/snsconverter/helpers.py index 44d01396..d3d6b040 100644 --- a/snsconverter/helpers.py +++ b/snsconverter/helpers.py @@ -103,8 +103,7 @@ def urls_to_string(links: list[str], socialMedia: SocialMedia): return "\n".join( [ "OwO what's this?", - f"*notices your terrible {socialMedia.value} embeds*", - "Here's a better alternative:", + f"*fixes your {socialMedia.value} embeds:*", *links, ] ) From 68e754e770144a933b1e59717e371bc842dce3a8 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 00:57:42 +0000 Subject: [PATCH 05/11] Add reddit and threads support --- snsconverter/commandHandlers.py | 4 +- snsconverter/constants.py | 15 +++- snsconverter/eventHandlers.py | 4 + snsconverter/eventsCore.py | 146 ++++++++++++++++++++++++++++++++ snsconverter/helpers.py | 49 ++++++++++- snsconverter/snsconverter.py | 2 +- 6 files changed, 212 insertions(+), 8 deletions(-) diff --git a/snsconverter/commandHandlers.py b/snsconverter/commandHandlers.py index fee53f02..9afa2f58 100644 --- a/snsconverter/commandHandlers.py +++ b/snsconverter/commandHandlers.py @@ -14,7 +14,7 @@ async def _grpSns(self, ctx: Context): async def _cmdToggle(self, ctx: Context): """Toggle SNSConverter replacements on the server - This will toggle the auto-reply of any Twitter, Instagram or Tiktok links with - embeds, and replace them with vxtwitter, ddinstagram or vxtiktok, respectively. + This will toggle the auto-reply of any Twitter, Instagram, Threads, Tiktok, or Reddit links with + embeds, and replace them with vxtwitter, ddinstagram, vxthreads, vxtiktok, or fxreddit respectively. """ await self.cmdToggle(ctx) diff --git a/snsconverter/constants.py b/snsconverter/constants.py index 3e1797bc..88f70f49 100644 --- a/snsconverter/constants.py +++ b/snsconverter/constants.py @@ -3,10 +3,15 @@ KEY_ENABLED = "enabled" DEFAULT_GUILD = {KEY_ENABLED: False} -INSTA_REGEX_PATTERN = re.compile(r"https://(?:www\.)?(instagram.com)") -TIKTOK_REGEX_PATTERN = re.compile(r"https://(www\.|vm\.)?(tiktok.com)") -TWITTER_REGEX_PATTERN = re.compile(r"https://(?:www\.|)twitter\.com(/[^/]+/status/\d+)") -X_REGEX_PATTERN = re.compile(r"https://(?:www\.|)x\.com(/[^/]+/status/\d+)") +INSTA_REGEX_PATTERN = re.compile(r"http(?:s)?://(?:www\.)?(instagram\.com)") +TIKTOK_REGEX_PATTERN = re.compile(r"http(?:s)?://(www\.|vm\.)?(tiktok\.com)") +TWITTER_REGEX_PATTERN = re.compile( + r"http(?:s)?://(?:www\.)?twitter\.com(/[^/]+/status/\d+)" +) +X_REGEX_PATTERN = re.compile(r"http(?:s)?://(?:www\.)?x\.com(/[^/]+/status/\d+)") +# Match any reddit subdomain, too many to list (old, np, de, us, etc) +REDDIT_REGEX_PATTERN = re.compile(r"http(?:s)?://(?:[\w-]+?\.)?reddit\.com") +THREADS_REGEX_PATTERN = re.compile(r"http(?:s)?://(?:www\.)?(threads\.net)") class SocialMedia(enum.Enum): @@ -14,3 +19,5 @@ class SocialMedia(enum.Enum): # I'm not calling it f****ng "x" lol TWITTER = "Twitter" TIKTOK = "TikTok" + REDDIT = "Reddit" + THREADS = "Threads" diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index 048e7bbd..9c7179ca 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -10,9 +10,13 @@ async def twit_replacer(self, message: Message): await self._on_message_twit_replacer(message) await self._on_message_insta_replacer(message) await self._on_message_tik_replacer(message) + await self._on_message_reddit_replacer(message) + await self._on_message_threads_replacer(message) @commands.Cog.listener("on_message_edit") async def twit_edit_replacer(self, message_before: Message, message_after): await self._on_edit_twit_replacer(message_before, message_after) await self._on_edit_insta_replacer(message_before, message_after) await self._on_edit_tik_replacer(message_before, message_after) + await self._on_edit_reddit_replacer(message_before, message_after) + await self._on_edit_threads_replacer(message_before, message_after) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 5c6b2404..5b5f903c 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -5,6 +5,8 @@ from .helpers import ( convert_to_ddinsta_url, convert_to_fx_twitter_url, + convert_to_rxddit_url, + convert_to_vx_threads_url, convert_to_vx_tiktok_url, urls_to_string, valid, @@ -200,3 +202,147 @@ async def _on_edit_tik_replacer( # Remove embeds from user message if reply is successful if ok: await message_after.edit(suppress=True) + + async def _on_message_reddit_replacer(self, message: Message): + if not valid(message): + return + + if not message.embeds: + return + + if not await self.config.guild(message.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message.guild.name, + message.guild.id, + ) + return + + # the actual code part + rxddit_urls = convert_to_rxddit_url(message.embeds) + + # no changed urls detected + if not rxddit_urls: + return + + # constructs the message and replies with a mention + ok = await message.reply(urls_to_string(rxddit_urls, SocialMedia.REDDIT)) + + # Remove embeds from user message if reply is successful + if ok: + await message.edit(suppress=True) + + async def _on_edit_reddit_replacer( + self, message_before: Message, message_after: Message + ): + # skips if the message is sent by any bot + if not valid(message_after): + return + + # skips if the message has no embeds + if not message_after.embeds: + return + + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message_after.guild.name, + message_after.guild.id, + ) + return + + video_embed_before = [embed for embed in message_before.embeds if embed.video] + video_embed_after = [embed for embed in message_after.embeds if embed.video] + new_video_embeds = [ + embed for embed in video_embed_after if embed not in video_embed_before + ] + + # skips if the message has no new embeds + if not new_video_embeds: + return + + rxddit_urls = convert_to_rxddit_url(new_video_embeds) + + # no changed urls detected + if not rxddit_urls: + return + + # constructs the message and replies with a mention + ok = await message_after.reply(urls_to_string(rxddit_urls, SocialMedia.REDDIT)) + + # Remove embeds from user message if reply is successful + if ok: + await message_after.edit(suppress=True) + + async def _on_message_threads_replacer(self, message: Message): + if not valid(message): + return + + if not message.embeds: + return + + if not await self.config.guild(message.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message.guild.name, + message.guild.id, + ) + return + + # the actual code part + vx_threads_urls = convert_to_vx_threads_url(message.embeds) + + # no changed urls detected + if not vx_threads_urls: + return + + # constructs the message and replies with a mention + ok = await message.reply(urls_to_string(vx_threads_urls, SocialMedia.THREADS)) + + # Remove embeds from user message if reply is successful + if ok: + await message.edit(suppress=True) + + async def _on_edit_threads_replacer( + self, message_before: Message, message_after: Message + ): + # skips if the message is sent by any bot + if not valid(message_after): + return + + # skips if the message has no embeds + if not message_after.embeds: + return + + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + self.logger.debug( + "SNSConverter disabled for guild %s (%s), skipping", + message_after.guild.name, + message_after.guild.id, + ) + return + + video_embed_before = [embed for embed in message_before.embeds if embed.video] + video_embed_after = [embed for embed in message_after.embeds if embed.video] + new_video_embeds = [ + embed for embed in video_embed_after if embed not in video_embed_before + ] + + # skips if the message has no new embeds + if not new_video_embeds: + return + + vx_threads_urls = convert_to_vx_threads_url(new_video_embeds) + + # no changed urls detected + if not vx_threads_urls: + return + + # constructs the message and replies with a mention + ok = await message_after.reply( + urls_to_string(vx_threads_urls, SocialMedia.THREADS) + ) + + # Remove embeds from user message if reply is successful + if ok: + await message_after.edit(suppress=True) diff --git a/snsconverter/helpers.py b/snsconverter/helpers.py index d3d6b040..ee07d7b8 100644 --- a/snsconverter/helpers.py +++ b/snsconverter/helpers.py @@ -4,6 +4,8 @@ from .constants import ( INSTA_REGEX_PATTERN, + REDDIT_REGEX_PATTERN, + THREADS_REGEX_PATTERN, TIKTOK_REGEX_PATTERN, TWITTER_REGEX_PATTERN, X_REGEX_PATTERN, @@ -72,7 +74,6 @@ def convert_to_fx_twitter_url(message_content: str): fixed_urls = [] - # Extracts all twitter urls from message content, and converts them to fxtwitter, returning a list of urls for word in message_split: # I don't think @everyone will work anyway, but just incase... if "@" in word: @@ -87,6 +88,52 @@ def convert_to_fx_twitter_url(message_content: str): return fixed_urls +def convert_to_rxddit_url(embeds: list[Embed]): + """ + Parameters + ---------- + embeds: list of Discord embeds + + Returns + ------- + filtered list of Reddit URLs that have been converted to rxddit + """ + + # pulls only video embeds from list of embeds + urls = [entry.url for entry in embeds] + + rxddit_urls = [ + re.sub(REDDIT_REGEX_PATTERN, r"https://rxddit.com", result) + for result in urls + if re.match(REDDIT_REGEX_PATTERN, result) + ] + + return rxddit_urls + + +def convert_to_vx_threads_url(embeds: list[Embed]): + """ + Parameters + ---------- + embeds: list of Discord embeds + + Returns + ------- + filtered list of Threads URLs that have been converted to vxthreads + """ + + # pulls only video embeds from list of embeds + urls = [entry.url for entry in embeds] + + vxthreads_urls = [ + re.sub(THREADS_REGEX_PATTERN, r"https://vx\1", result) + for result in urls + if re.match(THREADS_REGEX_PATTERN, result) + ] + + return vxthreads_urls + + def urls_to_string(links: list[str], socialMedia: SocialMedia): """ Parameters diff --git a/snsconverter/snsconverter.py b/snsconverter/snsconverter.py index e93cdc60..38a81e91 100644 --- a/snsconverter/snsconverter.py +++ b/snsconverter/snsconverter.py @@ -5,6 +5,6 @@ class SNSConverter(commands.Cog, CommandHandlers, EventHandlers): - """Converts Twitter, Instagram & Tiktok links for better video embeds""" + """Converts Twitter, Instagram, Threads, Tiktok & Reddit links for better embeds""" pass From 15ad868e00b1d7e368bcaeafb58002d14d80e488 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:28:51 +0000 Subject: [PATCH 06/11] Switch to raw_message_edit to fix embed lag issue --- snsconverter/eventHandlers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index 9c7179ca..9fc22fb3 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -13,7 +13,7 @@ async def twit_replacer(self, message: Message): await self._on_message_reddit_replacer(message) await self._on_message_threads_replacer(message) - @commands.Cog.listener("on_message_edit") + @commands.Cog.listener("on_raw_message_edit") async def twit_edit_replacer(self, message_before: Message, message_after): await self._on_edit_twit_replacer(message_before, message_after) await self._on_edit_insta_replacer(message_before, message_after) From 6614d75f89eceeb0b5aeea6b881563a163190197 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:47:19 +0000 Subject: [PATCH 07/11] Raw message fuckery --- snsconverter/eventHandlers.py | 14 ++-- snsconverter/eventsCore.py | 124 ++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index 9fc22fb3..b6d617dd 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -1,4 +1,4 @@ -from discord import Message +from discord import Message, RawMessageUpdateEvent from redbot.core import commands from .eventsCore import EventsCore @@ -14,9 +14,9 @@ async def twit_replacer(self, message: Message): await self._on_message_threads_replacer(message) @commands.Cog.listener("on_raw_message_edit") - async def twit_edit_replacer(self, message_before: Message, message_after): - await self._on_edit_twit_replacer(message_before, message_after) - await self._on_edit_insta_replacer(message_before, message_after) - await self._on_edit_tik_replacer(message_before, message_after) - await self._on_edit_reddit_replacer(message_before, message_after) - await self._on_edit_threads_replacer(message_before, message_after) + async def twit_edit_replacer(self, payload: RawMessageUpdateEvent): + await self._on_edit_twit_replacer(payload) + await self._on_edit_insta_replacer(payload) + await self._on_edit_tik_replacer(payload) + await self._on_edit_reddit_replacer(payload) + await self._on_edit_threads_replacer(payload) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 5b5f903c..73249589 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -1,4 +1,4 @@ -from discord import Message +from discord import Message, RawMessageUpdateEvent from .constants import KEY_ENABLED, SocialMedia from .core import Core @@ -42,28 +42,28 @@ async def _on_message_insta_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_insta_replacer( - self, message_before: Message, message_after: Message - ): - if not valid(message_after): + async def _on_edit_insta_replacer(self, payload: RawMessageUpdateEvent): + if not valid(payload.cached_message): return # skips if the message has no embeds - if not message_after.embeds: + if not payload.data["embeds"]: return - if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + if not await self.config.guild(payload.cached_message.guild).get_attr( + KEY_ENABLED + )(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - message_after.guild.name, - message_after.guild.id, + payload.cached_message.guild.name, + payload.cached_message.guild.id, ) return new_embeds = [ embed - for embed in message_after.embeds - if embed not in message_before.embeds + for embed in payload.data["embeds"] + if embed not in payload.cached_message.embeds ] # skips if the message has no new embeds @@ -76,13 +76,13 @@ async def _on_edit_insta_replacer( return # constructs the message and replies with a mention - ok = await message_after.reply( + ok = await payload.cached_message.reply( urls_to_string(ddinsta_urls, SocialMedia.INSTAGRAM) ) # Remove embeds from user message if reply is successful if ok: - await message_after.edit(suppress=True) + await payload.cached_message.edit(suppress=True) async def _on_message_twit_replacer(self, message: Message): if not valid(message): @@ -106,18 +106,18 @@ async def _on_message_twit_replacer(self, message: Message): # constructs the message and replies with a mention await message.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) - async def _on_edit_twit_replacer( - self, message_before: Message, message_after: Message - ): + async def _on_edit_twit_replacer(self, payload: RawMessageUpdateEvent): # skips if the message is sent by any bot - if not valid(message_after): + if not valid(payload.cached_message): return - if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + if not await self.config.guild(payload.cached_message.guild).get_attr( + KEY_ENABLED + )(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - message_after.guild.name, - message_after.guild.id, + payload.cached_message.guild.name, + payload.cached_message.guild.id, ) return @@ -128,7 +128,9 @@ async def _on_edit_twit_replacer( return # constructs the message and replies with a mention - await message_after.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) + await payload.cached_message.reply( + urls_to_string(fx_twtter_urls, SocialMedia.TWITTER) + ) async def _on_message_tik_replacer(self, message: Message): if not valid(message): @@ -159,27 +161,29 @@ async def _on_message_tik_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_tik_replacer( - self, message_before: Message, message_after: Message - ): + async def _on_edit_tik_replacer(self, payload: RawMessageUpdateEvent): # skips if the message is sent by any bot - if not valid(message_after): + if not valid(payload.cached_message): return # skips if the message has no embeds - if not message_after.embeds: + if not payload.data["embeds"]: return - if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + if not await self.config.guild(payload.cached_message.guild).get_attr( + KEY_ENABLED + )(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - message_after.guild.name, - message_after.guild.id, + payload.cached_message.guild.name, + payload.cached_message.guild.id, ) return - video_embed_before = [embed for embed in message_before.embeds if embed.video] - video_embed_after = [embed for embed in message_after.embeds if embed.video] + video_embed_before = [ + embed for embed in payload.cached_message.embeds if embed.video + ] + video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] new_video_embeds = [ embed for embed in video_embed_after if embed not in video_embed_before ] @@ -195,13 +199,13 @@ async def _on_edit_tik_replacer( return # constructs the message and replies with a mention - ok = await message_after.reply( + ok = await payload.cached_message.reply( urls_to_string(vx_tiktok_urls, SocialMedia.TIKTOK) ) # Remove embeds from user message if reply is successful if ok: - await message_after.edit(suppress=True) + await payload.cached_message.edit(suppress=True) async def _on_message_reddit_replacer(self, message: Message): if not valid(message): @@ -232,27 +236,29 @@ async def _on_message_reddit_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_reddit_replacer( - self, message_before: Message, message_after: Message - ): + async def _on_edit_reddit_replacer(self, payload: RawMessageUpdateEvent): # skips if the message is sent by any bot - if not valid(message_after): + if not valid(payload.cached_message): return # skips if the message has no embeds - if not message_after.embeds: + if not payload.data["embeds"]: return - if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + if not await self.config.guild(payload.cached_message.guild).get_attr( + KEY_ENABLED + )(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - message_after.guild.name, - message_after.guild.id, + payload.cached_message.guild.name, + payload.cached_message.guild.id, ) return - video_embed_before = [embed for embed in message_before.embeds if embed.video] - video_embed_after = [embed for embed in message_after.embeds if embed.video] + video_embed_before = [ + embed for embed in payload.cached_message.embeds if embed.video + ] + video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] new_video_embeds = [ embed for embed in video_embed_after if embed not in video_embed_before ] @@ -268,11 +274,13 @@ async def _on_edit_reddit_replacer( return # constructs the message and replies with a mention - ok = await message_after.reply(urls_to_string(rxddit_urls, SocialMedia.REDDIT)) + ok = await payload.cached_message.reply( + urls_to_string(rxddit_urls, SocialMedia.REDDIT) + ) # Remove embeds from user message if reply is successful if ok: - await message_after.edit(suppress=True) + await payload.cached_message.edit(suppress=True) async def _on_message_threads_replacer(self, message: Message): if not valid(message): @@ -303,27 +311,29 @@ async def _on_message_threads_replacer(self, message: Message): if ok: await message.edit(suppress=True) - async def _on_edit_threads_replacer( - self, message_before: Message, message_after: Message - ): + async def _on_edit_threads_replacer(self, payload: RawMessageUpdateEvent): # skips if the message is sent by any bot - if not valid(message_after): + if not valid(payload.cached_message): return # skips if the message has no embeds - if not message_after.embeds: + if not payload.data["embeds"]: return - if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): + if not await self.config.guild(payload.cached_message.guild).get_attr( + KEY_ENABLED + )(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - message_after.guild.name, - message_after.guild.id, + payload.cached_message.guild.name, + payload.cached_message.guild.id, ) return - video_embed_before = [embed for embed in message_before.embeds if embed.video] - video_embed_after = [embed for embed in message_after.embeds if embed.video] + video_embed_before = [ + embed for embed in payload.cached_message.embeds if embed.video + ] + video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] new_video_embeds = [ embed for embed in video_embed_after if embed not in video_embed_before ] @@ -339,10 +349,10 @@ async def _on_edit_threads_replacer( return # constructs the message and replies with a mention - ok = await message_after.reply( + ok = await payload.cached_message.reply( urls_to_string(vx_threads_urls, SocialMedia.THREADS) ) # Remove embeds from user message if reply is successful if ok: - await message_after.edit(suppress=True) + await payload.cached_message.edit(suppress=True) From 28853498bf4a231cc3e38fd02fb9c6402bff2bbb Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 01:49:33 +0000 Subject: [PATCH 08/11] Missed a message_after --- snsconverter/eventsCore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 73249589..60a42c05 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -121,7 +121,7 @@ async def _on_edit_twit_replacer(self, payload: RawMessageUpdateEvent): ) return - fx_twtter_urls = convert_to_fx_twitter_url(message_after.content) + fx_twtter_urls = convert_to_fx_twitter_url(payload.data["content"]) # no changed urls detected if not fx_twtter_urls: From 6264166280baf27914cb036e856dd9011a7a12d6 Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 02:02:06 +0000 Subject: [PATCH 09/11] Fix new embed finding --- snsconverter/eventsCore.py | 48 +++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 60a42c05..14bb962f 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -1,4 +1,4 @@ -from discord import Message, RawMessageUpdateEvent +from discord import Embed, Message, RawMessageUpdateEvent from .constants import KEY_ENABLED, SocialMedia from .core import Core @@ -61,9 +61,9 @@ async def _on_edit_insta_replacer(self, payload: RawMessageUpdateEvent): return new_embeds = [ - embed + Embed.from_dict(embed) for embed in payload.data["embeds"] - if embed not in payload.cached_message.embeds + if Embed.from_dict(embed) not in payload.cached_message.embeds ] # skips if the message has no new embeds @@ -180,19 +180,17 @@ async def _on_edit_tik_replacer(self, payload: RawMessageUpdateEvent): ) return - video_embed_before = [ - embed for embed in payload.cached_message.embeds if embed.video - ] - video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] - new_video_embeds = [ - embed for embed in video_embed_after if embed not in video_embed_before + new_embeds = [ + Embed.from_dict(embed) + for embed in payload.data["embeds"] + if Embed.from_dict(embed) not in payload.cached_message.embeds ] # skips if the message has no new embeds - if not new_video_embeds: + if not new_embeds: return - vx_tiktok_urls = convert_to_vx_tiktok_url(new_video_embeds) + vx_tiktok_urls = convert_to_vx_tiktok_url(new_embeds) # no changed urls detected if not vx_tiktok_urls: @@ -255,19 +253,17 @@ async def _on_edit_reddit_replacer(self, payload: RawMessageUpdateEvent): ) return - video_embed_before = [ - embed for embed in payload.cached_message.embeds if embed.video - ] - video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] - new_video_embeds = [ - embed for embed in video_embed_after if embed not in video_embed_before + new_embeds = [ + Embed.from_dict(embed) + for embed in payload.data["embeds"] + if Embed.from_dict(embed) not in payload.cached_message.embeds ] # skips if the message has no new embeds - if not new_video_embeds: + if not new_embeds: return - rxddit_urls = convert_to_rxddit_url(new_video_embeds) + rxddit_urls = convert_to_rxddit_url(new_embeds) # no changed urls detected if not rxddit_urls: @@ -330,19 +326,17 @@ async def _on_edit_threads_replacer(self, payload: RawMessageUpdateEvent): ) return - video_embed_before = [ - embed for embed in payload.cached_message.embeds if embed.video - ] - video_embed_after = [embed for embed in payload.data["embeds"] if embed.video] - new_video_embeds = [ - embed for embed in video_embed_after if embed not in video_embed_before + new_embeds = [ + Embed.from_dict(embed) + for embed in payload.data["embeds"] + if Embed.from_dict(embed) not in payload.cached_message.embeds ] # skips if the message has no new embeds - if not new_video_embeds: + if not new_embeds: return - vx_threads_urls = convert_to_vx_threads_url(new_video_embeds) + vx_threads_urls = convert_to_vx_threads_url(new_embeds) # no changed urls detected if not vx_threads_urls: From 04b07ffca50b9c901a218e1e59cc9f1612a5c02f Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 02:12:52 +0000 Subject: [PATCH 10/11] Revert twitter to standard on_message_edit Since payload.data["content"] is optional --- snsconverter/eventHandlers.py | 9 +++++++-- snsconverter/eventsCore.py | 20 +++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index b6d617dd..a52aa380 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -13,9 +13,14 @@ async def twit_replacer(self, message: Message): await self._on_message_reddit_replacer(message) await self._on_message_threads_replacer(message) + @commands.Cog.listener("on_message_edit") + async def twit_raw_edit_replacer( + self, message_before: Message, message_after: Message + ): + await self._on_edit_twit_replacer(message_before, message_after) + @commands.Cog.listener("on_raw_message_edit") - async def twit_edit_replacer(self, payload: RawMessageUpdateEvent): - await self._on_edit_twit_replacer(payload) + async def twit_raw_edit_replacer(self, payload: RawMessageUpdateEvent): await self._on_edit_insta_replacer(payload) await self._on_edit_tik_replacer(payload) await self._on_edit_reddit_replacer(payload) diff --git a/snsconverter/eventsCore.py b/snsconverter/eventsCore.py index 14bb962f..4ac2f7c2 100644 --- a/snsconverter/eventsCore.py +++ b/snsconverter/eventsCore.py @@ -106,31 +106,29 @@ async def _on_message_twit_replacer(self, message: Message): # constructs the message and replies with a mention await message.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) - async def _on_edit_twit_replacer(self, payload: RawMessageUpdateEvent): + async def _on_edit_twit_replacer( + self, message_before: Message, message_after: Message + ): # skips if the message is sent by any bot - if not valid(payload.cached_message): + if not valid(message_after): return - if not await self.config.guild(payload.cached_message.guild).get_attr( - KEY_ENABLED - )(): + if not await self.config.guild(message_after.guild).get_attr(KEY_ENABLED)(): self.logger.debug( "SNSConverter disabled for guild %s (%s), skipping", - payload.cached_message.guild.name, - payload.cached_message.guild.id, + message_after.guild.name, + message_after.guild.id, ) return - fx_twtter_urls = convert_to_fx_twitter_url(payload.data["content"]) + fx_twtter_urls = convert_to_fx_twitter_url(message_after.content) # no changed urls detected if not fx_twtter_urls: return # constructs the message and replies with a mention - await payload.cached_message.reply( - urls_to_string(fx_twtter_urls, SocialMedia.TWITTER) - ) + await message_after.reply(urls_to_string(fx_twtter_urls, SocialMedia.TWITTER)) async def _on_message_tik_replacer(self, message: Message): if not valid(message): From 31982096f3d6e03f4d11349a8add44edf18c247b Mon Sep 17 00:00:00 2001 From: DoctorDinosaur <26852749+DoctorDinosaur@users.noreply.github.com> Date: Sun, 12 Nov 2023 02:18:47 +0000 Subject: [PATCH 11/11] Consistent names, thanks copilot.. --- snsconverter/eventHandlers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/snsconverter/eventHandlers.py b/snsconverter/eventHandlers.py index a52aa380..a8ba0c76 100644 --- a/snsconverter/eventHandlers.py +++ b/snsconverter/eventHandlers.py @@ -14,9 +14,7 @@ async def twit_replacer(self, message: Message): await self._on_message_threads_replacer(message) @commands.Cog.listener("on_message_edit") - async def twit_raw_edit_replacer( - self, message_before: Message, message_after: Message - ): + async def twit_edit_replacer(self, message_before: Message, message_after: Message): await self._on_edit_twit_replacer(message_before, message_after) @commands.Cog.listener("on_raw_message_edit")