You've already forked JapariArchive
fresh start
This commit is contained in:
236
Discord/discordHelper.py
Normal file
236
Discord/discordHelper.py
Normal file
@@ -0,0 +1,236 @@
|
||||
from __future__ import annotations
|
||||
from datetime import datetime
|
||||
import html
|
||||
import io
|
||||
import re
|
||||
import nextcord
|
||||
from nextcord import ChannelType, Message
|
||||
|
||||
from Database.dbcontroller import DatabaseController
|
||||
from Database.x_classes import ErrorID, x_accounts
|
||||
from Twitter.tweetHelper import DownloadedMedia
|
||||
from exceptions import NO_CHANNEL, OTHER_ERROR
|
||||
from tweety.types.twDataTypes import Tweet
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from runtimeBotData import RuntimeBotData
|
||||
|
||||
def chunks(s, n):
|
||||
"""Produce `n`-character chunks from `s`."""
|
||||
for start in range(0, len(s), n):
|
||||
yield s[start:start+n]
|
||||
|
||||
def build_pixiv_embed(post):
|
||||
url = "https://www.pixiv.net/en/artworks/" + str(post.id)
|
||||
text = re.sub(r"https://t.co\S+", "", html.unescape(post.caption))
|
||||
date = post.create_date
|
||||
|
||||
embed=nextcord.Embed(description=text)
|
||||
embed.set_author(name=post.user.name, url=url)
|
||||
embed.set_footer(text=date)
|
||||
|
||||
return embed
|
||||
|
||||
def build_x_embed(handle : str, post : Tweet):
|
||||
url = "https://x.com/" + handle + "/status/" + str(post.id)
|
||||
text = re.sub(r"https://t.co\S+", "", html.unescape(post.text))
|
||||
date = datetime.strftime(post.created_on, '%Y-%m-%d %H:%M:%S')
|
||||
|
||||
embed=nextcord.Embed(description=text)
|
||||
embed.set_author(name=handle, url=url, icon_url=post.author.profile_image_url_https)
|
||||
embed.set_footer(text=date)
|
||||
|
||||
return embed
|
||||
|
||||
def build_secondary_embed(main_post : Message, handle : str, post : Tweet):
|
||||
text = re.sub(r"https://t.co\S+", "", html.unescape(post.text))
|
||||
date = datetime.strftime(post.created_on, '%Y-%m-%d %H:%M:%S')
|
||||
attachment_urls = [attachment.url.split("?")[0] for attachment in main_post.attachments]
|
||||
|
||||
embeds = []
|
||||
for url in attachment_urls:
|
||||
embed = nextcord.Embed(url="https://katworks.sytes.net")
|
||||
embed.set_image(url)
|
||||
embeds.append(embed)
|
||||
|
||||
if len(embeds) == 0:
|
||||
return None
|
||||
|
||||
embed : nextcord.Embed = embeds[0]
|
||||
embed.description = text
|
||||
embed.set_footer(text=date)
|
||||
embed.set_author(name=handle, url=main_post.jump_url, icon_url=post.author.profile_image_url_https)
|
||||
return embeds
|
||||
|
||||
async def send_error(ex : Exception, botData : RuntimeBotData):
|
||||
print(ex)
|
||||
errors_channel = nextcord.utils.get(botData.client.guilds[0].channels, name="bot-status")
|
||||
await errors_channel.send(content=str(ex))
|
||||
|
||||
def get_secondary_channel(is_animated, is_filtered, rating, tags : list, artist : x_accounts, guild : nextcord.Guild):
|
||||
if is_animated:
|
||||
return nextcord.utils.get(guild.channels, name="animation-feed")
|
||||
if artist.rating == 'NSFL':
|
||||
return nextcord.utils.get(guild.channels, name="hidden-feed")
|
||||
if "futanari" in tags:
|
||||
return nextcord.utils.get(guild.channels, name="hidden-feed")
|
||||
if is_filtered or not rating:
|
||||
return nextcord.utils.get(guild.channels, name="filtered-feed")
|
||||
if rating == "general":
|
||||
return nextcord.utils.get(guild.channels, name="safe-feed")
|
||||
if rating == "sensitive" or rating == "questionable":
|
||||
return nextcord.utils.get(guild.channels, name="unsafe-feed")
|
||||
if rating == 'explicit':
|
||||
return nextcord.utils.get(guild.channels, name="explicit-feed")
|
||||
|
||||
return nextcord.utils.get(guild.channels, name="filtered-feed")
|
||||
|
||||
async def edit_existing_embed_color(message : Message, color : nextcord.Colour):
|
||||
embeds = message.embeds
|
||||
embeds[0].colour = color
|
||||
await message.edit(embeds=embeds)
|
||||
|
||||
async def send_x_post(post : Tweet, artist : x_accounts, guild : nextcord.Guild, new_accounts : list, files_to_send : list[DownloadedMedia], is_filtered: bool, rating: str, tags : list, auto_approve : bool = False, vox_labels : list = None, duplicate_posts : list = None, xView: nextcord.ui.View = None, yView: nextcord.ui.View = None):
|
||||
if vox_labels is None:
|
||||
vox_labels = []
|
||||
if duplicate_posts is None:
|
||||
duplicate_posts = []
|
||||
|
||||
if artist.discord_channel_id != 0:
|
||||
channel = guild.get_channel(artist.discord_channel_id)
|
||||
elif artist.discord_thread_id != 0:
|
||||
channel = guild.get_thread(artist.discord_thread_id)
|
||||
else:
|
||||
raise NO_CHANNEL("Ensure channel for the account exists")
|
||||
|
||||
embed = build_x_embed(artist.name, post)
|
||||
if rating != "":
|
||||
embed.add_field(name = "rating", value=rating, inline=False)
|
||||
embed.add_field(name = "tags", value=f'{", ".join(tags)}'.replace("_","\\_")[:1024], inline=False)
|
||||
if len(duplicate_posts) > 0:
|
||||
links = [f"[{id}](<https://fxtwitter.com/i/status/{id}>)" for id in duplicate_posts]
|
||||
embed.add_field(name = "duplicates", value=f'{" ".join(links)}'[:1024], inline=False)
|
||||
|
||||
discord_files = [nextcord.File(fp = io.BytesIO(x.file_bytes), filename = x.file_name, force_close=True) for x in files_to_send]
|
||||
try:
|
||||
main_post : Message = await channel.send(embed=embed, files=discord_files)
|
||||
except Exception as e:
|
||||
raise OTHER_ERROR(e)
|
||||
finally:
|
||||
for file in discord_files: file.close()
|
||||
|
||||
#skip posting in the public feed for accounts with too many posts
|
||||
if artist.name in new_accounts and not is_filtered:
|
||||
return main_post
|
||||
|
||||
is_animated = files_to_send[0].file_name.endswith(".mp4")
|
||||
secondary_channel : nextcord.TextChannel = get_secondary_channel(is_animated, is_filtered, rating, tags, artist, guild)
|
||||
|
||||
if is_animated:
|
||||
link = "https://vxtwitter.com/" + artist.name + "/status/" + post.id + " " + main_post.jump_url
|
||||
secondary_post : Message = await secondary_channel.send(content=link, view = None if auto_approve else yView)
|
||||
else:
|
||||
embeds = build_secondary_embed(main_post, artist.name, post)
|
||||
if rating != "":
|
||||
embeds[0].add_field(name = "rating", value=rating, inline=False)
|
||||
#embeds[0].add_field(name = "tags", value=f'{", ".join(tags)}'.replace("_","\\_")[:1024], inline=False)
|
||||
if len(vox_labels) > 0:
|
||||
embeds[0].add_field(name = "prediction", value=", ".join(vox_labels), inline=False)
|
||||
if len(duplicate_posts) > 0:
|
||||
links = [f"[{id}](<https://fxtwitter.com/i/status/{id}>)" for id in duplicate_posts]
|
||||
embeds[0].add_field(name = "duplicates", value=f'{" ".join(links)}'[:1024], inline=False)
|
||||
secondary_post : Message = await secondary_channel.send(embeds=embeds, view = None if auto_approve else xView)
|
||||
|
||||
return main_post
|
||||
|
||||
async def send_pixiv_post(post, files_to_send, channel : nextcord.TextChannel):
|
||||
embed = build_pixiv_embed(post)
|
||||
|
||||
discord_files = [nextcord.File(fp = io.BytesIO(file["file"]), filename = file["name"], force_close=True) for file in files_to_send]
|
||||
try:
|
||||
main_post : Message = await channel.send(embed=embed, files=discord_files)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return None, ErrorID.OTHER_ERROR
|
||||
finally:
|
||||
for file in discord_files: file.close()
|
||||
|
||||
return main_post, ErrorID.SUCCESS
|
||||
|
||||
async def post_result(results, guild : nextcord.Guild, new_accounts : list):
|
||||
print("Results: ", len(results))
|
||||
channel = nextcord.utils.get(guild.channels, name="bot-status")
|
||||
string = f'Last check: {datetime.now().strftime("%d/%m/%Y %H:%M:%S")}'
|
||||
for result in results:
|
||||
if result in new_accounts:
|
||||
string += f'\n{result} (new): {results[result]}'
|
||||
new_accounts.remove(result)
|
||||
else:
|
||||
string += f'\n{result}: {results[result]}'
|
||||
|
||||
for chunk in chunks(string, 6000):
|
||||
embed = nextcord.Embed(description=chunk)
|
||||
await channel.send(embed=embed)
|
||||
|
||||
async def get_channel_from_handle(guild: nextcord.Guild, handle : str):
|
||||
channel = nextcord.utils.get(guild.channels, name=handle.lower())
|
||||
if channel is None:
|
||||
catId = 0
|
||||
category = None
|
||||
while category is None or len(category.channels) == 50:
|
||||
category = nextcord.utils.get(guild.categories, name=f'TWITTER-{catId}')
|
||||
if category is None:
|
||||
category = await guild.create_category(f'TWITTER-{catId}')
|
||||
catId+=1
|
||||
channel = await guild.create_text_channel(name=handle.lower(), category=category)
|
||||
return channel
|
||||
|
||||
async def get_thread_from_handle(guild: nextcord.Guild, handle : str):
|
||||
channel = nextcord.utils.get(guild.channels, name="threads")
|
||||
thread = nextcord.utils.get(channel.threads, name=handle.lower())
|
||||
if thread is None:
|
||||
thread = await channel.create_thread(name=handle.lower(), auto_archive_duration=10080, type=ChannelType.public_thread)
|
||||
return thread
|
||||
|
||||
async def get_category_by_name(client: nextcord.Client, name):
|
||||
guild = client.guilds[0]
|
||||
category = nextcord.utils.get(guild.categories, name=name)
|
||||
if category is None:
|
||||
category = await guild.create_category(name)
|
||||
return category
|
||||
|
||||
def check_permission(interaction : nextcord.Interaction):
|
||||
role = nextcord.utils.find(lambda r: r.name == 'Archivist', interaction.guild.roles)
|
||||
return role in interaction.user.roles
|
||||
|
||||
async def message_from_jump_url(server : nextcord.Guild, jump_url:str):
|
||||
link = jump_url.split('/')
|
||||
server_id = int(link[4])
|
||||
channel_id = int(link[5])
|
||||
msg_id = int(link[6])
|
||||
|
||||
channel = server.get_channel(channel_id)
|
||||
if channel is None:
|
||||
channel = server.get_thread(channel_id)
|
||||
message = await channel.fetch_message(msg_id)
|
||||
return message
|
||||
|
||||
async def get_main_post_and_data(guild, jump_url, botData : RuntimeBotData):
|
||||
main_post = await message_from_jump_url(guild, jump_url)
|
||||
tw_embed = main_post.embeds[0]
|
||||
x_post_id = int(tw_embed.author.url.split('/')[-1])
|
||||
return main_post, x_post_id
|
||||
|
||||
async def ensure_has_channel_or_thread(artist: x_accounts, guild: nextcord.Guild, database: DatabaseController):
|
||||
if artist.discord_channel_id == 0 and artist.discord_thread_id == 0:
|
||||
try:
|
||||
channel = await get_channel_from_handle(guild, artist.name)
|
||||
artist.discord_channel_id = channel.id
|
||||
artist.discord_thread_id = 0
|
||||
except:
|
||||
thread = await get_thread_from_handle(guild, artist.name)
|
||||
artist.discord_thread_id = thread.id
|
||||
artist.discord_channel_id = 0
|
||||
|
||||
database.x_update_account(artist)
|
||||
105
Discord/views.py
Normal file
105
Discord/views.py
Normal file
@@ -0,0 +1,105 @@
|
||||
from __future__ import annotations
|
||||
import nextcord
|
||||
from nextcord.ui import View
|
||||
from Database.x_classes import ActionTaken
|
||||
from Discord import discordHelper
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from runtimeBotData import RuntimeBotData
|
||||
|
||||
class XView(View):
|
||||
def __init__(self, botData : RuntimeBotData):
|
||||
self.botData = botData
|
||||
super().__init__(timeout=None, prevent_update=False)
|
||||
|
||||
@nextcord.ui.button(label="KF Art", custom_id="button-keep", style=nextcord.ButtonStyle.gray)
|
||||
async def button_keep(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.embeds[0].author.url, self.botData)
|
||||
self.botData.db.x_update_post(x_post_id, main_post.id, 0, ActionTaken.Accepted)
|
||||
await discordHelper.edit_existing_embed_color(main_post, nextcord.Colour.green())
|
||||
await self_message.edit(view=None)
|
||||
|
||||
@nextcord.ui.button(label="Non-KF Art", custom_id="button-hide", style=nextcord.ButtonStyle.gray)
|
||||
async def button_hide(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.embeds[0].author.url, self.botData)
|
||||
self.botData.db.x_update_post(x_post_id, main_post.id, 0, ActionTaken.Hidden)
|
||||
await discordHelper.edit_existing_embed_color(main_post, nextcord.Colour.yellow())
|
||||
await self_message.delete()
|
||||
|
||||
@nextcord.ui.button(label="Delete", custom_id="button-delete", style=nextcord.ButtonStyle.gray)
|
||||
async def button_delete(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
try:
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.embeds[0].author.url, self.botData)
|
||||
print("Deleting", x_post_id, main_post.jump_url)
|
||||
|
||||
await main_post.delete()
|
||||
await self_message.delete()
|
||||
|
||||
self.botData.db.x_update_post(x_post_id, 0, 0, ActionTaken.Rejected)
|
||||
except Exception as e:
|
||||
await interaction.response.send_message("Error occured " + str(e), ephemeral=False)
|
||||
|
||||
class YView(View):
|
||||
|
||||
def __init__(self, botData : RuntimeBotData):
|
||||
self.botData = botData
|
||||
super().__init__(timeout=None, prevent_update=False)
|
||||
|
||||
@nextcord.ui.button(label="KF Art", custom_id="y-button-keep", style=nextcord.ButtonStyle.gray)
|
||||
async def button_keep(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.content.split(" ")[1], self.botData)
|
||||
self.botData.db.x_update_post(x_post_id, main_post.id, 0, ActionTaken.Accepted)
|
||||
await discordHelper.edit_existing_embed_color(main_post, nextcord.Colour.green())
|
||||
await self_message.edit(view=None)
|
||||
|
||||
@nextcord.ui.button(label="Non-KF Art", custom_id="y-button-hide", style=nextcord.ButtonStyle.gray)
|
||||
async def button_hide(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.content.split(" ")[1], self.botData)
|
||||
self.botData.db.x_update_post(x_post_id, main_post.id, 0, ActionTaken.Hidden)
|
||||
await discordHelper.edit_existing_embed_color(main_post, nextcord.Colour.yellow())
|
||||
await self_message.delete()
|
||||
|
||||
@nextcord.ui.button(label="Delete", custom_id="y-button-delete", style=nextcord.ButtonStyle.gray)
|
||||
async def button_delete(self, button, interaction : nextcord.Interaction):
|
||||
if not discordHelper.check_permission(interaction):
|
||||
await interaction.response.send_message("No permission", ephemeral=True)
|
||||
return
|
||||
|
||||
try:
|
||||
self_message = interaction.message
|
||||
main_post, x_post_id = await discordHelper.get_main_post_and_data(interaction.guild, self_message.content.split(" ")[1], self.botData)
|
||||
print("Deleting", x_post_id, main_post.jump_url)
|
||||
|
||||
await main_post.delete()
|
||||
await self_message.delete()
|
||||
|
||||
self.botData.db.x_update_post(x_post_id, 0, 0, ActionTaken.Rejected)
|
||||
except Exception as e:
|
||||
await interaction.response.send_message("Error occured " + str(e), ephemeral=False)
|
||||
|
||||
Reference in New Issue
Block a user