diff --git a/config_example.json b/config_example.json new file mode 100644 index 0000000..a5fcfc6 --- /dev/null +++ b/config_example.json @@ -0,0 +1,260 @@ +{ + "token": "", + "debug": false, + "guild": 0, + "admins": [], + "channels": { + "nsfw": { + "access": 0, + "ass": 0, + "ass_2d": 0, + "tits": 0, + "tits_2d": 0 + }, + "verification": { + "captcha": 0, + "captcha_log": 0, + "verification": 0, + "additional_verification": 0 + }, + "general": { + "chat": 0, + "art": 0 + } + }, + "roles": { + "nsfw": 0, + "admin": 0, + "verified": 0, + "failed_captcha": 0, + "additional_verification": 0 + }, + "msg": { + "denied": "Команду можуть виконувати лише адміністратори", + "denied_guild": "Команда працює лише на сервері Crue-11 Raise" + }, + "auto_nsfw": [ + { + "channel": 0, + "booru": "3d", + "tags": "ass", + "limit": 60 + }, + { + "channel": 0, + "booru": "3d", + "tags": "boobs", + "limit": 60 + }, + { + "channel": 0, + "booru": "2d", + "tags": "ass", + "limit": 60 + }, + { + "channel": 0, + "booru": "2d", + "tags": "boobs", + "limit": 60 + } + ], + "forbidden_replies": [ + "русский военный корабль, иди нахуй" + ], + "forbidden_answers": [ + "славароссии", + "славаросии", + "славаросси", + "славаросії", + "славарф", + "славаросеи", + "пошёлтынахуй", + "пошёлнахуй", + "пошелнахуй", + "идинах", + "пошелтынахуй", + "славапутину", + "славасоветскомусоюзу", + "славассср", + "путинбог", + "путінбог", + "говно", + "хуйня", + "хуй", + "славапутіну" + ], + "captchas": [ + { + "question": "Як умру", + "answer": [ + "то поховайте" + ] + }, + { + "question": "Хіба ревуть воли", + "answer": [ + "як ясла повні" + ] + }, + { + "question": "Слуга", + "answer": [ + "народу" + ] + }, + { + "question": "Олені, Олені", + "answer": [ + "небриті і неголені" + ] + }, + { + "question": "У всякого своя доля", + "answer": [ + "І свій шлях широкий" + ] + }, + { + "question": "Хто ти, човне? Що шукаєш?", + "answer": [ + "Відки і куди пливеш", + "Звідки і куди пливеш", + "Відки й куди пливеш", + "Звідки й куди пливеш" + ] + }, + { + "question": "Доброго вечора", + "answer": [ + "Ми з України", + "Ми з Украіни" + ] + }, + { + "question": "Душу й тіло ми положим", + "answer": [ + "за нашу свободу" + ] + }, + { + "question": "Згинуть наші вороженьки", + "answer": [ + "як роса на сонці" + ] + }, + { + "question": "Садок вишневий", + "answer": [ + "коло хати" + ] + }, + { + "question": "Ой, хто п'є", + "answer": [ + "Тому наливайте" + ] + }, + { + "question": "Хто не п'є", + "answer": [ + "Тому не давайте" + ] + }, + { + "question": "Ой Житомир", + "answer": [ + "це не місто не село", + "то не місто не село" + ] + }, + { + "question": "Файне місто", + "answer": [ + "Тернопіль" + ] + }, + { + "question": "Хто покаже в чарці дно", + "answer": [ + "Тому щастя і добро", + "Тому щастя й добро" + ] + }, + { + "question": "Батько наш Бандера", + "answer": [ + "Україна мати", + "Україна - мати", + "Украіна мати", + "Украіна - мати", + "Україна – мати", + "Украіна – мати", + "Україна — мати", + "Украіна — мати" + ] + }, + { + "question": "Ми за Україну", + "answer": [ + "підем воювати", + "будем воювати" + ] + }, + { + "question": "Зродились ми", + "answer": [ + "великої години", + "великої годинки" + ] + }, + { + "question": "Ах, Бандеро", + "answer": [ + "Український апостол", + "Украінський апостол", + "Тобі жилось непросто", + "Народний наш герой" + ] + }, + { + "question": "Той мурує", + "answer": [ + "той руйнує" + ] + }, + { + "question": "Як умру то поховайте", + "answer": [ + "мене на могилі" + ] + }, + { + "question": "Серед степу широкого", + "answer": [ + "На Вкраїні милій", + "На Вкраіні милій" + ] + }, + { + "question": "Щоб лани широкополі", + "answer": [ + "І Дніпро, і кручі", + "І Дніпро і кручі" + ] + }, + { + "question": "Ой у лузі", + "answer": [ + "Червона калина" + ] + }, + { + "question": "Чогось наша славна Україна", + "answer": [ + "зажурилася", + "зажурилась" + ] + } + ] +} \ No newline at end of file diff --git a/dsbot.py b/dsbot.py new file mode 100644 index 0000000..e19dee5 --- /dev/null +++ b/dsbot.py @@ -0,0 +1,6 @@ +@client.slash_command(name="link", description="Connect to your AutoZoom") +async def nazi(ctx: discord.ApplicationContext, code: discord.Option(str, "Code you got in AutoZoom app")): + + + +client.run(getConfig("token")) \ No newline at end of file diff --git a/glorybot.py b/glorybot.py new file mode 100644 index 0000000..b0e6f87 --- /dev/null +++ b/glorybot.py @@ -0,0 +1,592 @@ +import asyncio +from datetime import datetime +from random import choice +import time +import traceback +import discord, json # type: ignore +import os + +from modules.booruGet import booruGet + +from discord import Embed, ButtonStyle, ApplicationContext, Option # type: ignore +from discord.enums import ChannelType # type: ignore + +#from discord_slash import SlashCommand, SlashContext + +intents = discord.Intents().all() +client = discord.Bot(intents=intents) + +# Technical ============================================================================================================== +def nowtime(): + return datetime.now().strftime("%d.%m.%Y | %H:%M:%S") + +def logWrite(message): + print(f"[{nowtime()}] {message}") + +def jsonSave(filename, value): + with open(filename, 'w', encoding="utf-8") as f: + json.dump(value, f, indent=4, ensure_ascii=False) + f.close() + +def jsonLoad(filename): + with open(filename, 'r', encoding="utf-8") as f: + value = json.load(f) + f.close() + return value +#========================================================================================================================= + + +# Configuration ========================================================================================================== +def configGet(key: str, *args: str): + this_dict = jsonLoad("config.json") + this_key = this_dict + for dict_key in args: + this_key = this_key[dict_key] + return this_key[key] + +def configSet(key, value): + config = jsonLoad("config.json") + config[key] = value + jsonSave("config.json", config) +#========================================================================================================================= + + +# Discord Utils ========================================================================================================== +def getChan(channels, id): + return discord.utils.get(channels, id=id) + +async def rmMsg(channel_id, message_id): + try: + channel = client.get_channel(channel_id) + message = await channel.fetch_message(message_id) + await message.delete() + except: + pass + +def makeEmbed(title="", description="", footer="", image=None, color=0xffffff): + embed=Embed(title=title, description=description, color=color) + if footer is not None: + embed.set_footer(text=footer) + if image is not None: + embed.set_image(url=image) + return embed +#========================================================================================================================= + + +# Booru Function ========================================================================================================= +async def booruAuto(channel, booru, tags, limit): + try: + output = await booruGet(booru, tags, limit=limit) + if output["kind"] == "image" and output["error"] == "": + await channel.send( + embed=makeEmbed(image=output["image"], footer=f'Теги: {output["tags"]}', color=0x2400e8), + view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Джерело Фото", url=output["source"])) + ) + elif output["kind"] == "video" and output["thumbnail"] != "": + await channel.send( + embed=makeEmbed(image=output["thumbnail"], footer=f'Теги: {output["tags"]}', color=0x2400e8), + view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Дивитись Відео", url=output["source"])) + ) + except: + # traceback.print_exc() + pass + +async def booruCommand(ctx, booru, tags, limit, page, times): + for _ in range(times): + try: + output = await booruGet(booru, tags, limit=limit, page=page) + if output["kind"] == "image" and output["error"] == "": + await ctx.respond( + embed=makeEmbed(image=output["image"], footer=f'Теги: {output["tags"]}', color=0x2400e8), + view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Джерело Фото", url=output["source"])) + ) + elif output["kind"] == "video" and output["thumbnail"] != "": + await ctx.respond( + embed=makeEmbed(image=output["thumbnail"], footer=f'Теги: {output["tags"]}', color=0x2400e8), + view=discord.ui.View(discord.ui.Button(style=ButtonStyle.link, label="Дивитись Відео", url=output["source"])) + ) + else: + traceback.print_exc() + if configGet("debug"): + await ctx.respond(embed=makeEmbed(image=output["image"], footer="Exception: "+output["error"], color=0xf74b3a)) + else: + await ctx.respond(embed=makeEmbed(image=output["image"], color=0xf74b3a)) + except: + # traceback.print_exc() + pass + await asyncio.sleep(.25) +#========================================================================================================================= + +# Auto Nudes Sender ====================================================================================================== +async def sendNudes(): + + await client.wait_until_ready() + guild = client.get_guild(configGet("guild")) + + while True: + for entry in configGet("auto_nsfw"): + await booruAuto(getChan(guild.channels, entry["channel"]), entry["booru"], entry["tags"], entry["limit"]) + await asyncio.sleep(.25) + await asyncio.sleep(60) +#========================================================================================================================= + +# @client.slash_command(name="autonsfw", description="2д пікча з бордів за тегом") +# async def autonsfw( +# ctx: ApplicationContext, +# booru: Option(str, "Назва booru сервісу", choices=["realbooru", "yandere", "danbooru", "konachan", "rule34"]), # type: ignore +# tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore +# limit: Option(int, "Сторінки (Кількість зображень/сторінку) (20 якщо не задано)", required=False, default=20), # type: ignore +# page: Option(int, "Номер сторінки результатів (Рандомна якщо не задано)", required=False, default=None), # type: ignore +# cooldown: Option(int, "Затримка між запитами", required=False, default=1, min_value=1, max_value=5) # type: ignore +# ): +# await booruCommand(ctx, "2d", tags, limit, page, times) + +# NSFW Commands ========================================================================================================== +nsfw = client.create_group("nsfw", "Команди з відвертим вмістом") + +@nsfw.command(name="2d", description="2д пікча з бордів за тегом") +async def nsfw_2d( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "2d", tags, limit, page, times) + +@nsfw.command(name="3d", description="3д пікча з бордів за тегом") +async def nsfw_3d( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "3d", tags, limit, page, times) + +@nsfw.command(name="yandere", description="Пікча з yande.re за тегом") +async def nsfw_yandere( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "yandere", tags, limit, page, times) + +@nsfw.command(name="konachan", description="Пікча з konachan.com за тегом") +async def nsfw_konachan( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "konachan", tags, limit, page, times) + +@nsfw.command(name="danbooru", description="Пікча з danbooru.donmai.us за тегом") +async def nsfw_danbooru( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "danbooru", tags, limit, page, times) + +@nsfw.command(name="rule34", description="Пікча rule34.xxx за тегом") +async def nsfw_rule34( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "rule34", tags, limit, page, times) + +@nsfw.command(name="realbooru", description="Пікча з realbooru.com за тегом") +async def nsfw_realbooru( + ctx: ApplicationContext, + tags: Option(str, "Теги (через пробіл)", required=False, default=""), # type: ignore + limit: Option(int, "Сторінки (Кількість зображень/сторінку)", required=False, default=20), # type: ignore + page: Option(int, "Номер сторінки результатів", required=False, default=None), # type: ignore + times: Option(int, "Кількість бажаних зображень", required=False, default=1, min_value=1, max_value=5) # type: ignore + ): + await booruCommand(ctx, "realbooru", tags, limit, page, times) +#========================================================================================================================= + + +async def pidozra(ctx, user, reason="Не вказана"): + + userdata = jsonLoad("data.json") + + if str(user.id) not in userdata["dms"]: + captcha = choice(configGet("captchas")) + userdata["dms"][str(user.id)] = {} + userdata["dms"][str(user.id)]["captcha"] = captcha + else: + captcha = userdata["dms"][str(user.id)]["captcha"] + + logWrite(f"User {user.name}#{user.discriminator} manually sent to verification due to '{reason}' (q: '{captcha['question']}' a: {str(captcha['answer'])})") + + try: + sent_msg = await user.send(content=f"{user.mention} Вибачте, але вам потрібно пройти невеличкий тест для продовження користування сервером Crue-11 Raise\n\n**{captcha['question']} ...**\n\n```\nПродовжіть речення або надішліть правильну відповідь щоб пройти перевірку\n```") + if not isinstance(ctx, discord.Message): + await ctx.respond(content=f"Юзеру `{user.name}#{user.discriminator}` оголешно про підозру") + except Exception as exp: + if not isinstance(ctx, discord.Message): + await ctx.respond(content=f"Не вдалось оголосити `{user.name}#{user.discriminator}` про підозру:\n`{exp}`") + return + + + await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="❓ Відправлено на перевірку", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Причина:** `{reason}`\n**Питання:** `{captcha['question']}`\n**Відповіді:** `{str(captcha['answer'])}`", color=0x6996e4)) + + await user.remove_roles(getChan(user.guild.roles, configGet("verified", "roles"))) + await user.add_roles(getChan(user.guild.roles, configGet("additional_verification", "roles"))) + + userdata["dms"][str(user.id)]["question_id"] = sent_msg.id + + jsonSave("data.json", userdata) + + +@client.event +async def on_ready(): + + print(f"Logged in as {client.user}") + await client.change_presence(activity=discord.Activity(type=discord.ActivityType.listening, name="Гімн України")) + await sendNudes() + +# Guild Commands ========================================================================================================= +@client.slash_command(name="verify", description="Підтвердити що юзер не московит") +async def verify(ctx: ApplicationContext, user: Option(discord.User, "Юзер сервера")): # type: ignore + + if ctx.author.id in configGet("admins"): + + if ctx.guild is not None: + + userdata = jsonLoad("data.json") + + logWrite(f"User {user.name}#{user.discriminator} verified by admin {ctx.author.name}#{ctx.author.discriminator}") + + await ctx.respond(content=f"{user.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!", delete_after=3) + + await user.add_roles(getChan(user.guild.roles, configGet("verified", "roles"))) + + await getChan(user.guild.channels, configGet("chat", "channels", "general")).send(content=f"У нас поповнення у вигляді {user.mention}. Познайомтесь :)") + + await user.remove_roles(getChan(user.guild.roles, configGet("failed_captcha", "roles"))) + + await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера верифіковано вручну", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Адмін**: `{ctx.author.name}#{ctx.author.discriminator}`", color=0xffc300)) + + try: + del userdata[str(user.id)] + jsonSave("data.json", userdata) + except: + pass + + return + else: + await ctx.respond(content=configGet("denied_guild", "msg")) + else: + await ctx.respond(content=configGet("denied", "msg")) + +@client.slash_command(name="pidozra", description="Оголосити юзеру про підозру") +async def pidozra_cmd(ctx: ApplicationContext, user: Option(discord.User, "Юзер сервера"), reason: Option(str, "Причина", required=False, default="Не вказана")): # type: ignore + + if ctx.author.id in configGet("admins"): + if ctx.guild is not None: + await pidozra(ctx, user, reason=reason) + else: + await ctx.respond(content=configGet("denied_guild", "msg")) + else: + await ctx.respond(content=configGet("denied", "msg")) + +@client.slash_command(name="nazi", description="Денацифікувати обраного московита") +async def nazi(ctx: ApplicationContext, user: Option(discord.User, "Обраний московит")): # type: ignore + + if ctx.author.id in configGet("admins"): + + if ctx.guild is not None: + + userdata = jsonLoad("data.json") + + logWrite(f"User {user.name}#{user.discriminator} was sent to russian warship by {ctx.author.name}#{ctx.author.discriminator}") + + await ctx.respond(content=f"{user.mention} {choice(configGet('forbidden_replies'))}", delete_after=4) + + await asyncio.sleep(3) + + await user.ban(reason="Московит йобаний", delete_message_days=3) + + await getChan(user.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзера послано нахуй", description=f"**Ім'я:** `{user.name}#{user.discriminator}`\n**Адмін:** `{ctx.author.name}#{ctx.author.discriminator}`", color=0xea3319)) + + try: + del userdata[str(user.id)] + jsonSave("data.json", userdata) + except: + pass + + return + + else: + await ctx.respond(content=configGet("denied_guild", "msg")) + else: + await ctx.respond(content=configGet("denied", "msg")) +#========================================================================================================================= + + +# Utility Commands ======================================================================================================= +@client.slash_command(name="debug", description="Переключити режим відлагодження") +async def debug(ctx: ApplicationContext, value: Option(bool, "Стан режиму")): # type: ignore + + if ctx.author.id in configGet("admins"): + configSet("debug", value) + logWrite(f"User {ctx.author.name}#{ctx.author.discriminator} set debug mode to {str(value)}") + await ctx.respond(content=f"Режим відлагодження змінено на `{str(value)}`") + else: + await ctx.respond(content=configGet("denied", "msg")) + +@client.slash_command(name="reboot", description="Перезапустити бота") +async def reboot(ctx: ApplicationContext): + + if ctx.author.id in configGet("admins"): + logWrite(f"User {ctx.author.name}#{ctx.author.discriminator} called reboot") + await ctx.respond(content=f"Вимикаюсь з номером процесу `{os.getpid()}`") + os.system(f"kill -9 {os.getpid()}") + else: + await ctx.respond(content=configGet("denied", "msg")) +#========================================================================================================================= + + +# Discord Events ========================================================================================================= +@client.event +async def on_member_join(member): + + userdata = jsonLoad("data.json") + + if str(member.id) not in userdata: + captcha = choice(configGet("captchas")) + userdata[str(member.id)] = {} + userdata[str(member.id)]["captcha"] = captcha + else: + captcha = userdata[str(member.id)]["captcha"] + + logWrite(f"User {member.name}#{member.discriminator} joined with (q: '{captcha['question']}' a: {str(captcha['answer'])})") + + await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🆕 Юзер зайшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{captcha['question']}`\n**Відповіді:** `{str(captcha['answer'])}`", color=0x6996e4)) + await asyncio.sleep(3) + + sent_msg = await getChan(member.guild.channels, configGet("captcha", "channels", "verification")).send(content=f"{member.mention} Ласкаво просимо!\n\n**{captcha['question']} ...**\n\n```\nПродовжіть речення або надішліть правильну відповідь щоб пройти перевірку\n```", delete_after=1800) + + userdata[str(member.id)]["question_id"] = sent_msg.id + jsonSave("data.json", userdata) + + await asyncio.sleep(300) + userdata = jsonLoad("data.json") + + if str(member.id) in userdata: + try: + logWrite(f"User {member.name}#{member.discriminator} ignored verification (q: '{userdata[str(member.id)]['captcha']['question']}' a: {str(userdata[str(member.id)]['captcha']['answer'])})") + await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🔇 Юзер проігнорував тест", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{userdata[str(member.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata[str(member.id)]['captcha']['answer'])}`", color=0xffc300)) + await getChan(member.guild.channels, configGet("captcha", "channels", "verification")).send(content=f"{member.mention} Тест проігноровано, до побачення", delete_after=4) + await asyncio.sleep(3) + await member.kick(reason="Ігнорування вступного тесту") + del userdata[str(member.id)] + jsonSave("data.json", userdata) + except: + traceback.print_exc() + +@client.event +async def on_member_remove(member): + + logWrite(f"User {member.name}#{member.discriminator} left") + + userdata = jsonLoad("data.json") + + if str(member.id) in userdata: + + try: + await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🚪 Юзер вийшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`\n**Питання:** `{userdata[str(member.id)]['question']}`\n**Відповіді:** `{str(userdata[str(member.id)]['answer'])}`", color=0x6996e4)) + except: + await getChan(member.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="🚪 Юзер вийшов", description=f"**Ім'я:** `{member.name}#{member.discriminator}`", color=0x6996e4)) + + if "question_id" in userdata[str(member.id)]: + await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(member.id)]["question_id"]) + del userdata[str(member.id)]["question_id"] + + if userdata[str(member.id)] == {}: + del userdata[str(member.id)] + + jsonSave("data.json", userdata) + +@client.event +async def on_raw_reaction_add(payload): + if payload.channel_id == configGet("access", "channels", "nsfw"): + if str(payload.emoji) == "✅": + logWrite(f"User {payload.member.name}#{payload.member.discriminator} gets NSFW role") + await payload.member.add_roles(getChan(payload.member.guild.roles, configGet("nsfw", "roles"))) + +@client.event +async def on_raw_reaction_remove(payload): + user = discord.utils.get(client.get_all_members(), id=payload.user_id) + if payload.channel_id == configGet("access", "channels", "nsfw"): + if str(payload.emoji) == "✅": + logWrite(f"User {user.name}#{user.discriminator} lost NSFW role") + await user.remove_roles(getChan(user.guild.roles, configGet("nsfw", "roles"))) + +@client.event +async def on_message(message): + + userdata = jsonLoad("data.json") + + if message.channel.id == configGet("art", "channels", "general"): + + await message.add_reaction('🔺') + await message.add_reaction('🔻') + + thread = await message.create_thread(name=f"{message.author.name} ({datetime.now().strftime('%d.%m.%Y')})", auto_archive_duration=10080) + await thread.send(content="**Гілку для коментарів створено!**\nНадсилайте коментарі до цієї роботи/фотографії користуючись гілкою.") + + elif message.channel.id == configGet("captcha", "channels", "verification"): + + if message.author != client.user: + + for answer in userdata[str(message.author.id)]["captcha"]["answer"]: + + if answer.lower().replace(" ", "") in message.content.lower().replace(" ", "").replace(",", "").replace(".", ""): + + logWrite(f"User {message.author.name}#{message.author.discriminator} verified") + + await message.reply(content=f"{message.author.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!", delete_after=3) + + await message.delete() + await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"]) + + await message.author.add_roles(getChan(message.guild.roles, configGet("verified", "roles"))) + + await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера верифіковано", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xffc300)) + + await getChan(message.author.guild.channels, configGet("chat", "channels", "general")).send(content=f"У нас поповнення у вигляді {message.author.mention}. Познайомтесь :)") + + del userdata[str(message.author.id)]["captcha"] + del userdata[str(message.author.id)] + + jsonSave("data.json", userdata) + return + + if message.content.lower().replace(" ", "") in configGet("forbidden_answers"): + + logWrite(f"User {message.author.name}#{message.author.discriminator} was piece of shit and replied '{message.content}'") + + await message.reply(content=f"{message.author.mention} {choice(configGet('forbidden_replies'))}", delete_after=4) + + await message.delete() + await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"]) + + await asyncio.sleep(3) + + await message.author.ban(reason="Московит йобаний", delete_message_days=1) + + await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер руснявий виблядок", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xea3319)) + + del userdata[str(message.author.id)]["captcha"] + del userdata[str(message.author.id)] + + jsonSave("data.json", userdata) + return + + else: + + logWrite(f"User {message.author.name}#{message.author.discriminator} failed verification (q: '{userdata[str(message.author.id)]['captcha']['question']}' a: {str(userdata[str(message.author.id)]['captcha']['answer'])} replied: '{message.content}')") + + await message.reply(content=f"{message.author.mention} відповідь неправильна!\nВідправляйтесь у канал {getChan(message.guild.channels, configGet('verification', 'channels', 'verification')).mention}", delete_after=3) + await getChan(message.guild.channels, configGet("verification", "channels", "verification")).send(content=f"Користувач {message.author.mention} потребує перевірки {getChan(message.guild.roles, configGet('admin', 'roles')).mention}\n\nПитання: `{userdata[str(message.author.id)]['captcha']['question']}`\nВідповідь: `{str(userdata[str(message.author.id)]['captcha']['answer'])}`\n\nВідповів: `{message.content}`", delete_after=300) + + await message.delete() + await rmMsg(configGet("captcha", "channels", "verification"), userdata[str(message.author.id)]["question_id"]) + await asyncio.sleep(1) + + await message.author.add_roles(getChan(message.guild.roles, configGet("failed_captcha", "roles"))) + + await getChan(message.author.guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер не пройшов", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata[str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata[str(message.author.id)]['captcha']['answer'])}`", color=0xea3319)) + + del userdata[str(message.author.id)]["captcha"] + del userdata[str(message.author.id)] + + jsonSave("data.json", userdata) + return + + elif isinstance(message.channel, discord.DMChannel) and str(message.author.id) in userdata["dms"]: + + guild = client.get_guild(configGet("guild")) + member = guild.get_member(message.author.id) + + for answer in userdata["dms"][str(message.author.id)]["captcha"]["answer"]: + + if answer.lower().replace(" ", "") in message.content.lower().replace(" ", "").replace(",", "").replace(".", ""): + + logWrite(f"User {message.author.name}#{message.author.discriminator} additionally verified") + + await message.reply(content=f"{message.author.mention} Ласкаво просимо!\nУ вас тепер є повний доступ до всього сервера. Приємного спілкування!") + + #await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"]) + + await member.add_roles(guild.get_role(configGet("verified", "roles"))) + await member.remove_roles(guild.get_role(configGet("additional_verification", "roles"))) + + await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="✅ Юзера додатково верифіковано", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xffc300)) + + del userdata["dms"][str(message.author.id)]["captcha"] + del userdata["dms"][str(message.author.id)] + + jsonSave("data.json", userdata) + return + + if message.content.lower().replace(" ", "") in configGet("forbidden_answers"): + + logWrite(f"User {message.author.name}#{message.author.discriminator} was piece of shit and replied '{message.content}'") + + await message.reply(content=f"{choice(configGet('forbidden_replies'))}") + + await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"]) + + await member.ban(reason="Московит йобаний", delete_message_days=7) + + await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер руснявий виблядок", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xea3319)) + + del userdata["dms"][str(message.author.id)]["captcha"] + del userdata["dms"][str(message.author.id)] + + jsonSave("data.json", userdata) + return + + else: + + logWrite(f"User {message.author.name}#{message.author.discriminator} failed verification (q: '{userdata['dms'][str(message.author.id)]['captcha']['question']}' a: {str(userdata['dms'][str(message.author.id)]['captcha']['answer'])} replied: '{message.content}')") + + await message.reply(content=f"{message.author.mention} відповідь неправильна!\nВідправляйтесь у канал {getChan(guild.channels, configGet('verification', 'channels', 'verification')).mention}") + await getChan(guild.channels, configGet("verification", "channels", "verification")).send(content=f"Користувач {message.author.mention} потребує перевірки {getChan(guild.roles, configGet('admin_id')).mention}", delete_after=300) + + await rmMsg(message.channel.id, userdata["dms"][str(message.author.id)]["question_id"]) + + await asyncio.sleep(2) + + await member.add_roles(guild.get_role(configGet("failed_captcha", "roles"))) + await member.remove_roles(guild.get_role(configGet("additional_verification", "roles"))) + + await getChan(guild.channels, configGet("captcha_log", "channels", "verification")).send(embed=makeEmbed(title="☠ Юзер не пройшов", description=f"**Ім'я:** `{message.author.name}#{message.author.discriminator}`\n**Питання:** `{userdata['dms'][str(message.author.id)]['captcha']['question']}`\n**Відповів:** `{message.content}`\n**Правильні відповіді:** `{str(userdata['dms'][str(message.author.id)]['captcha']['answer'])}`", color=0xea3319)) + + del userdata["dms"][str(message.author.id)]["captcha"] + del userdata["dms"][str(message.author.id)] + + jsonSave("data.json", userdata) + return + + if "🇷🇺" in message.content: + + await pidozra(message, message.author, "Прапор московитів") + await message.delete() + return +#========================================================================================================================= + +client.run(configGet("token")) \ No newline at end of file diff --git a/modules/booruGet.py b/modules/booruGet.py new file mode 100644 index 0000000..38d6070 --- /dev/null +++ b/modules/booruGet.py @@ -0,0 +1,111 @@ +import json +import traceback +import requests +import webbrowser +import random +import asyncio +import xml.etree.ElementTree as ET + +async def booruGet(booru, tags, page=None, limit=30): + + try: + + booru_list = ["realbooru", "yandere", "danbooru", "konachan", "rule34"] + real_list = ["realbooru"] + anime_list = ["yandere", "danbooru", "konachan"] + + thumbnail = "" + + if page is None: + page = random.randint(0, 30) + + if booru == "2d": + booru = random.choice(anime_list) + elif booru == "3d": + booru = random.choice(real_list) + elif booru == "random" or booru not in booru_list: + booru = random.choice(booru_list) + + if booru == "realbooru": + + url = f"https://realbooru.com/index.php?page=dapi&s=post&q=index&limit={limit}&pid={page}&tags={tags}" + base_url = "https://realbooru.com/images/" + thumbnail_url = "https://realbooru.com/thumbnails/" + + post = random.choice(ET.fromstring(requests.get(url).text)) + file_format = post.get("file_url").split(".")[-1] + thumb_format = post.get("preview_url").split(".")[-1] + md5 = post.get("md5") + output = f"{md5[:2]}/{md5[2:4]}/{md5}.{file_format}" + output_thumb = f"{md5[:2]}/{md5[2:4]}/thumbnail_{md5}.{thumb_format}" + + image = source = base_url+output + thumbnail = thumbnail_url+output_thumb + + tags = post.get("tags") + + elif booru == "yandere": + + url = f"https://yande.re/post.json?limit={limit}&tags={tags}&page={page}" + output = random.choice(json.loads(requests.get(url).text)) + + image = output["sample_url"] + source = output["file_url"] + + tags = output["tags"] + + elif booru == "danbooru": + + url = f"https://danbooru.donmai.us/posts.json?&page={page}&tags={tags}&limit={limit}" + output = random.choice(json.loads(requests.get(url).text)) + + image = output["large_file_url"] + source = output["file_url"] + + tags = output["tag_string"] + + elif booru == "konachan": + + url = f"https://konachan.com/post.json?&page={page}&tags={tags}&limit={limit}" + output = random.choice(json.loads(requests.get(url).text)) + + image = output["sample_url"] + source = output["file_url"] + + tags = output["tags"] + + elif booru == "rule34": + + url = f"https://api.rule34.xxx/index.php?page=dapi&s=post&q=index&limit={limit}&pid={page}&tags={tags}&json=1" + print(url) + print(requests.get(url).json) + output = random.choice(json.loads(requests.get(url).json)) + + image = output["sample_url"] + source = output["file_url"] + + tags = output["tags"] + + if (".jpg" in image) or (".png" in image) or (".webp" in image) or (".jpeg" in image) or (".gif" in image): + kind = "image" + else: + kind = "video" + + return {"image": image, "thumbnail": thumbnail, "source": source, "kind": kind, "tags": tags.strip(), "error": ""} + + except IndexError: + + return {"image": "http://res.end-play.xyz/discord/invalid.jpg", "thumbnail": "", "source": "N/A", "kind": "image", "tags": "", "error": "Found page with such tags is empty.\nDecrease images limit or page number and try again."} + + except Exception as exp: + + return {"image": "http://res.end-play.xyz/discord/invalid.jpg", "thumbnail": "", "source": "N/A", "kind": "image", "tags": "", "error": str(traceback.format_exc())} + +if __name__ == "__main__": + + booru = input("Input booru: ") + tags = input("Input tags: ") + + url = asyncio.run(booruGet(booru, tags)) + print(url) + webbrowser.open(url["image"]) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e8209b5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +py-cord~=2.3.2 +requests~=2.28.1 \ No newline at end of file diff --git a/scheduled.json b/scheduled.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/scheduled.json @@ -0,0 +1 @@ +[] \ No newline at end of file