Initialize project

This commit is contained in:
Дмитрий Шиманский
2024-02-22 19:04:48 +03:00
commit ae43a31e39
29 changed files with 2156 additions and 0 deletions

44
.github/workflows/docker-push.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Publish Docker image
on:
release:
types: [published]
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
push_to_registries:
name: Push Docker image to multiple registries
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: |
ghcr.io/${{ github.repository }}
- name: Build and push Docker images
uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Dima YaFlay
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

12
README.md Normal file
View File

@@ -0,0 +1,12 @@
# Aoyo
Aoyo is multifunctional discord bot, worked on disnake, supports localization and audit log(indev), 50% string objects is russian language
# Bot can:
1. Create ticket(and save then)
2. Mute|Unmute user
3. Create custom voice channel with setuping(using bot alright)
4. Give report command to user (Right button on mouse on user or message)
5. Save channel
6. Localizations
# Support
If u know some languages(English, Spanish, etc.), u can help to localize this bot (create pull or issue)

123
cogs/auditChannel.py Normal file
View File

@@ -0,0 +1,123 @@
from disnake.ext import commands
from log import rootLogger
from handlers import *
import datetime
class audit(commands.Cog):
def __init__(self, bot):
self.bot = bot
rootLogger.info(f"{self.__class__.__name__} подключен")
@bot.event
async def on_guild_channel_create(channel):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "logs" in data["guilds"][f"{channel.guild.id}"]:
embed = disnake.Embed(title="Создание канала", description=f"Создан канал: {channel.name}! \n Категория канала: {channel.category.name}", timestamp=datetime.datetime.now())
await bot.get_channel(data["guilds"][f"{channel.guild.id}"]["logs"]).send(embed=embed)
@bot.event
async def on_guild_channel_update(before, after):
channel = before
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
after_changed = []
before_changed = []
if before.position != after.position:
after_changed.append(f"Position: {after.position}")
before_changed.append(f"Position: {before.position}")
if before.changed_roles != after.changed_roles:
after_changed.append(f'Roles: {after.changed_roles}')
before_changed.append(f'Roles: {before.changed_roles}')
if before.overwrites != after.overwrites:
for item in after.overwrites:
after_changed_perms = list(iter(after.overwrites[item].pair()[0]))
a_item_mention = item.mention
for item in before.overwrites:
before_changed_perms = list(iter(before.overwrites[item].pair()[0]))
for item in range(len(before_changed_perms)):
if after_changed_perms[item][1] != before_changed_perms[item][1]:
before_changed.append({a_item_mention: before_changed_perms[item]})
after_changed.append({a_item_mention: after_changed_perms[item]})
if before.name != after.name:
after_changed.append(f'Name: {after.name}')
before_changed.append(f'Name: {before.name}')
after_changed = str(after_changed).replace("'", '').replace('{', '').replace('}', '').replace('[', '').replace(']', '')
before_changed = str(before_changed).replace("'", '').replace("{", '').replace("}", '').replace('[', '').replace(']', '')
print(after_changed)
if "logs" in data["guilds"][f"{channel.guild.id}"]:
embed = disnake.Embed(title="Создание канала",
description=f"Изменен канал: {channel.name}! \nКатегория канала: {channel.category.name};\nИзмененные настройки до: {before_changed};\nИзмененные настройки после: {after_changed};",
timestamp=datetime.datetime.now())
await bot.get_channel(data["guilds"][f"{channel.guild.id}"]["logs"]).send(embed=embed)
@bot.event
async def on_guild_channel_delete(channel):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "logs" in data["guilds"][f"{channel.guild.id}"]:
embed = disnake.Embed(title="Удаление канала", description=f"Удален канал: {channel.name}! \n Категория канала: {channel.category.name}", timestamp=datetime.datetime.now())
await bot.get_channel(data["guilds"][f"{channel.guild.id}"]["logs"]).send(embed=embed)
@bot.event
async def on_message_edit(before, after):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "logs" in data["guilds"][f"{before.guild.id}"] and before.content != after.content:
embed = disnake.Embed(title="Изменение сообщения.", description=f"Автор: {before.author.mention}\n Канал: {before.channel.name}",timestamp=datetime.datetime.now(), color=0x00ff00)
embed.add_field(name="Сообщение до: ", value=before.content, inline=True)
embed.add_field(name="Сообщение после: ", value=after.content, inline=True)
embed.set_thumbnail(url=before.author.avatar)
await bot.get_channel(data["guilds"][f"{before.guild.id}"]["logs"]).send(embed=embed)
@bot.event
async def on_message_delete(message):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "logs" in data["guilds"][f"{message.guild.id}"]:
embed = disnake.Embed(title="Удаление сообщения.", description=f"Автор: {message.author.mention}\n Канал: {message.channel.name}\n Сообщение: {message.content}",timestamp=datetime.datetime.now(), color=disnake.Colour.from_rgb(186, 0, 6))
embed.set_thumbnail(url=message.author.avatar)
await bot.get_channel(data["guilds"][f"{message.guild.id}"]["logs"]).send(embed=embed)
@bot.event
async def on_member_update(before, after):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "logs" in data["guilds"][f"{before.guild.id}"]:
if len(before.roles) > len(after.roles) or len(before.roles) < len(after.roles):
embed = disnake.Embed(title="Изменение ролей.", description=f"Пользователь: {before.mention}",timestamp=datetime.datetime.now(), color=0x00ff00)
rolesBefore = []
rolesAfter = []
for role in before.roles:
rolesBefore.append(role.mention)
for role in after.roles:
rolesAfter.append(role.mention)
embed.add_field(name="Роли до: ", value=str(rolesBefore).replace('[', '').replace(']', '').replace("'", ''), inline=True)
embed.add_field(name="Роли после: ", value=str(rolesAfter).replace('[', '').replace(']', '').replace("'", ''), inline=True)
embed.set_thumbnail(url=before.avatar)
if len(rolesAfter) > len(rolesBefore):
for role in before.roles:
try:
rolesAfter.remove(role.mention)
except:
pass
embed.add_field(name="Измененная роль:", value=str(rolesAfter).replace('[', '').replace(']', '').replace("'", ''))
else:
for role in after.roles:
try:
rolesBefore.remove(role.mention)
except:
pass
embed.add_field(name="Измененная роль:", value=str(rolesBefore).replace('[', '').replace(']', '').replace("'", ''))
await bot.get_channel(data["guilds"][f"{before.guild.id}"]["logs"]).send(embed=embed)
def setup(bot):
bot.add_cog(audit(bot))

102
cogs/automatization.py Normal file
View File

@@ -0,0 +1,102 @@
from handlers import *
from disnake.ext import commands, tasks
import disnake
from datetime import datetime
from log import rootLogger
import pyspw
import json
import aiogram
from aiogram import types
class automatization(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.mutes.start()
rootLogger.info("Starting automatization...")
@tasks.loop(seconds=60.0)
async def mutes(self):
thisTime = datetime.now().strftime("%d/%m/%Y %H:%M")
path = Path("mute.json")
userData = json.loads(path.read_text(encoding="utf-8"))
if f"{thisTime}" in userData["mutes"]:
for items in userData["mutes"][f"{thisTime}"]:
guild = self.bot.get_guild(int(userData["mutes"][f"{thisTime}"][items]["guild"]))
member = await guild.fetch_member(int(userData["mutes"][f"{thisTime}"][items]["user"]))
await member.remove_roles(disnake.utils.get(guild.roles, id = int(takeSettings(guild.id, "mute_role"))))
del userData["mutes"][f"{thisTime}"]
path.write_text(json.dumps(userData, indent=4, ensure_ascii=False), encoding="utf-8", newline="\n")
@bot.listen()
async def on_message(message: disnake.Message):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if "autoreaction" in data["guilds"][f"{message.guild.id}"] and not message.author.bot:
if f"{message.channel.id}" in data["guilds"][f"{message.guild.id}"]["autoreaction"]:
reaction1 = bot.get_emoji(int(data["guilds"][f"{message.guild.id}"]["autoreaction"][f"{message.channel.id}"]["reaction1"]))
await message.add_reaction(reaction1)
try:
reaction2 = bot.get_emoji(int(data["guilds"][f"{message.guild.id}"]["autoreaction"][f"{message.channel.id}"]["reaction2"]))
await message.add_reaction(reaction2)
except: pass
if "autobrench" in data["guilds"][f"{message.guild.id}"] and not message.author.bot:
if f"{message.channel.id}" in data["guilds"][f"{message.guild.id}"]["autobrench"]:
await message.create_thread(name='Autobranch')
@bot.event
async def on_member_join(member):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
guildData = data["guilds"][f"{member.guild.id}"]
onJoinRole = disnake.utils.get(member.guild.roles, id = int(takeSettings(member.guild.id, "on_join_role")))
if "guest_room" in guildData or guildData["server"] != ["None", {}]:
if "guest_room" in guildData:
channelGuestRoom = bot.get_channel(int(guildData["guest_room"]))
try:
description = guildData["guest_text"].format(user=member.mention)
except:
description = guildData["guest_text"]
emb = disnake.Embed(title=f"**Привет, {member.name}!**", description=description, colour=disnake.Colour.from_rgb(47, 49, 54))
try:
emb.set_image(url=guildData["image_url"])
except:
print()
if guildData["server"] != ["None", {}]:
if guildData["server"]["server"] == "POOP":
try:
api = pyspw.SpApi(card_id=api_id, card_token=api_token).get_user(member.id).nickname
except:
print('Api error.... Again')
if api:
await member.edit(nick=api)
await member.add_roles(bot.get_guild(member.guild.id).get_role(int(guildData["server"]["role"])))
if "guest_room" in guildData:
emb.set_footer(text=f"Игрок подтвержден! Ник: {api}")
else:
if "guest_room" in guildData:
emb.set_footer(text=f"Игрок не подтвержден!")
else:
await member.add_roles(onJoinRole)
if "guest_room" in guildData:
await channelGuestRoom.send(member.mention,embed=emb)
@bot.event
async def on_member_remove(member):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
guildData = data["guilds"][f"{member.guild.id}"]
if "image" in guildData:
channelGuestRoom = bot.get_channel(int(takeSettings(member.guild.id, "guest_room")))
emb = disnake.Embed(title=f"**Пока-пока, {member.name}!**", colour=disnake.Colour.from_rgb(47, 49, 54))
emb.set_image(url=guildData["image"])
emb.set_footer(text="Ждем тебя снова!")
await channelGuestRoom.send(embed=emb)
def setup(bot):
bot.add_cog(automatization(bot))

281
cogs/buttons.py Normal file
View File

@@ -0,0 +1,281 @@
from disnake.ext import commands
import disnake
import json
from pathlib import Path
import pyspw
from disnake import TextInputStyle
from handlers import api_id, api_token, takeSettings, bot
from asyncio import sleep
from random import randint
import datetime
import chat_exporter
import io
class buttons(commands.Cog):
def __init__(self, bot):
self.bot = bot
@bot.listen("on_button_click")
async def button(inter: disnake.MessageInteraction):
if inter.component.custom_id in ['role1', 'role2', 'role3']:
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
role = bot.get_guild(inter.guild.id).get_role(data["guilds"][f"{inter.guild.id}"]['issues'][f"{inter.message.id}"][inter.component.custom_id])
await inter.author.add_roles(role)
await inter.response.send_message(f'{role.mention} вам выдалась!', ephemeral=True)
elif inter.component.custom_id == "buttonOnModal":
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
modalData = data["guilds"][f"{inter.guild.id}"]["modals"][f"{inter.channel.id}"][f"{inter.message.id}"]
if data["guilds"][f"{inter.guild.id}"]["server"] != {}:
try:
api = pyspw.SpApi(card_id=api_id, card_token=api_token).get_user(inter.author.id).nickname
custom_id="customModal-api"
except Exception:
api = None
custom_id = "customModal"
component=[
disnake.ui.TextInput(
label=modalData["0"],
custom_id=modalData["0"],
style=TextInputStyle.short,
),
]
for i in range(len(modalData)-3):
i = i + 1
modalDatas = modalData[f"{i}"]
component.append(
disnake.ui.TextInput(
label=f"{modalDatas}",
custom_id=f"{modalDatas}",
style=TextInputStyle.short,
),
)
await inter.response.send_modal(
title="Aoyo Modal System",
custom_id=custom_id,
components=component,)
elif inter.component.custom_id in ["closePrivateRoom", "hidePrivateRoom"]:
guild = bot.get_guild(inter.guild.id)
role = guild.get_role(int(takeSettings(inter.guild.id, "on_join_role")))
member = inter.author
if inter.component.custom_id == "closePrivateRoom":
overwrites = {
guild.default_role: disnake.PermissionOverwrite(connect=False),
role: disnake.PermissionOverwrite(connect=False),
member: disnake.PermissionOverwrite(connect=True)
}
else:
overwrites = {
guild.default_role: disnake.PermissionOverwrite(view_channel=False),
role: disnake.PermissionOverwrite(view_channel=False),
member: disnake.PermissionOverwrite(view_channel=True)
}
await bot.get_channel(inter.channel.id).edit(overwrites=overwrites)
await inter.response.send_message("Готово.", ephemeral=True)
elif inter.component.custom_id in ["giveOwner", "kickUser", "deleteChannel"]:
path = Path("tempFiles/voiceTempFile.json")
data = json.loads(path.read_text(encoding="utf-8"))
if int(data["voice_channels"][f"{inter.channel.id}"]["channel_owner"]) == inter.author.id:
if inter.component.custom_id == "giveOwner": await inter.response.send_message("Отправьте пинг игрока, которому хотите передать права", ephemeral=True)
elif inter.component.custom_id == "deleteChannel": await inter.channel.delete()
else: await inter.response.send_message("Отправьте пинг игрока, которого хотите кикннуть", ephemeral=True)
def check(m):
return m.author == inter.author and m.channel == inter.channel
try:
message = await bot.wait_for('message', timeout=30.0, check=check)
except TimeoutError:
return
else:
content = message.mentions[0].id
await message.delete()
if inter.component.custom_id == "giveOwner":
data["voice_channels"][f"{inter.channel.id}"]["channel_owner"] = content
data["voice_channels"][f"{inter.channel.id}"]["old_channel_owner"] = inter.author.id
path.write_text(json.dumps(data, indent=6), encoding="utf-8", newline="\n")
await inter.response.send_message(f"Готово! Владелец канала теперь: <@{content}>", ephemeral=True)
else:
member = await bot.get_guild(inter.guild.id).fetch_member(int(content))
await member.edit(voice_channel=None)
await inter.response.send_message(f"Готово! <@{content}> был кикнут", ephemeral=True)
else:
await inter.response.send_message("Вы не создатель канала!", ephemeral=True)
elif inter.component.custom_id == "takeOwner":
path = Path("tempFiles/voiceTempFile.json")
data = json.loads(path.read_text(encoding="utf-8"))
if data["voice_channels"][f"{inter.channel.id}"]["old_channel_owner"] == inter.author.id:
data["voice_channels"][f"{inter.channel.id}"]["channel_owner"] = inter.author.id
path.write_text(json.dumps(data, indent=6), encoding="utf-8", newline="\n")
await inter.response.send_message(f"Готово! Владелец канала теперь: <@{inter.author.id}>", ephemeral=True)
elif inter.component.custom_id == "renamePrivateRoom":
await inter.response.send_modal(
title="Aoyo Modal System",
custom_id="renamePrivateRoom",
components=[
disnake.ui.TextInput(
label='Новое название канала:',
placeholder="Я люблю нюхать бебру",
custom_id='newNamePrivateRoom',
style=disnake.TextInputStyle.short,
)
],
)
elif inter.component.custom_id == "setUsersLimit":
await inter.response.send_modal(
title="Aoyo Modal System",
custom_id="setUsersLimit",
components=[
disnake.ui.TextInput(
label='Новое максимальное кол-во пользователей:',
placeholder="1",
custom_id='newUserLimit',
style=disnake.TextInputStyle.short,
)
],
)
# tickets
elif inter.component.custom_id in ["firstTicket", "secondTicket", "thirdTicket", "createTicket", "reportCreateTicket"]:
path = Path("guilds/guilds.json")
ticketData = Path("tempFiles/ticket.json")
aJsonData = json.loads(path.read_text(encoding="utf-8"))
fromJsonData = json.loads(path.read_text(encoding="utf-8")).get('guilds')[f"{inter.guild_id}"]
toJsonData = json.loads(ticketData.read_text(encoding="utf-8"))
mention = inter.author.mention
if inter.component.custom_id == "firstTicket":
role = fromJsonData["ticket"][f"{inter.channel.id}"][f"{inter.message.id}"]["first_role"]
if inter.component.custom_id == "secondTicket":
role = fromJsonData["ticket"][f"{inter.channel.id}"][f"{inter.message.id}"]["second_role"]
if inter.component.custom_id == "thirdTicket":
role = fromJsonData["ticket"][f"{inter.channel.id}"][f"{inter.message.id}"]["third_role"]
if inter.component.custom_id == "reportCreateTicket":
role = fromJsonData["moderation_role"]
embedMessage = inter.message.embeds[0]
mention = f"<@{embedMessage.footer.text}> \n{inter.author.mention}"
await inter.message.edit(components=[
disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="reportAccept", label="Принять"),
disnake.ui.Button(label="Создать тикет", style=disnake.ButtonStyle.success, custom_id="reportCreateTicket", disabled=True),
disnake.ui.Button(label="Удалить репорт", style=disnake.ButtonStyle.danger, custom_id="deleteReport"),
],)
embed = disnake.Embed(title="Управление тикетом", description="Если вы готовы завершить тикет, нажмите ниже.", colour=disnake.Color.blue())
buttons = disnake.ui.View()
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="closeTicket", label="Закрыть тикет"))
guild = bot.get_guild(inter.guild.id)
roleOverwrite = guild.get_role(int(takeSettings(inter.guild.id, "on_join_role")))
roleTicket = guild.get_role(int(role))
overwrites = {
guild.default_role: disnake.PermissionOverwrite(view_channel=False),
roleOverwrite: disnake.PermissionOverwrite(view_channel=False),
inter.author: disnake.PermissionOverwrite(view_channel=True),
roleTicket: disnake.PermissionOverwrite(view_channel=True)
}
if not fromJsonData['ticket'].get('counter'):
aJsonData['guilds'][f'{inter.guild.id}']['ticket']['counter'] = 1
aJsonData['guilds'][f'{inter.guild.id}']['ticket']['counter'] = int(aJsonData['guilds'][f'{inter.guild.id}']['ticket']['counter']) + 1
count = aJsonData['guilds'][f'{inter.guild.id}']['ticket']['counter']
category = disnake.utils.get(guild.categories, id=inter.channel.category.id)
channel = await guild.create_text_channel(name=f"ticket-{count}", category=category, overwrites=overwrites)
await channel.send(content=f"{mention}\n<@&{role}>",embed=embed, view=buttons)
newJsonData = {
"channel_owner": f"{inter.author.mention}",
"channel_name": f"{channel.name}",
"panel": f"{inter.component.custom_id}"
}
if not toJsonData["ticket"].get(f"{inter.guild_id}"):
toJsonData["ticket"][f"{inter.guild_id}"] = {}
toJsonData["ticket"][f"{inter.guild_id}"][f"{channel.id}"] = newJsonData
if inter.component.custom_id == "reportCreateTicket":
toJsonData["ticket"][f"{inter.guild_id}"][f"{channel.id}"]["user_name"] = f"{embedMessage.footer.text}"
path.write_text(json.dumps(aJsonData, indent=3), encoding="utf-8", newline="\n")
ticketData.write_text(json.dumps(toJsonData, indent=3), encoding="utf-8", newline="\n")
await inter.response.send_message(f'Ваш тикет: {channel.mention}', ephemeral=True)
elif inter.component.custom_id == "closeTicket":
embed = disnake.Embed(title="Подтверждение", description=f"Вы уверены, что хотите закрыть тикет, {inter.author.name}?")
buttons = disnake.ui.View()
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="closeTicketPerm", label="Да, закрыть тикет"))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="cancelCloseTicket", label="Нет"))
await inter.response.send_message(embed=embed, view=buttons)
await inter.message.edit(components=[
disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="closeTicket", label="Закрыть тикет", disabled=True),
],)
elif inter.component.custom_id == "cancelCloseTicket":
for message in (await inter.channel.history(limit=None, oldest_first=True).flatten()):
msg = await bot.get_channel(inter.channel.id).fetch_message(message.id)
break
await msg.edit(components=[
disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="closeTicket", label="Закрыть тикет", disabled=False),
],)
await inter.message.delete()
elif inter.component.custom_id == "closeTicketPerm":
embed = disnake.Embed(title='**Aoyo ticket system**', description=f'Канал закрыт {inter.author.mention}', color=0x00ff00)
embed.set_image('https://media.discordapp.net/attachments/876280751488909332/979778066417070151/Frame_280.png?width=1440&height=4')
buttons = disnake.ui.View().add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id='deleteChannelTicket', label='Удалить канал'))
channel = bot.get_channel(inter.channel.id)
overwrites = {
inter.author: disnake.PermissionOverwrite(view_channel=False),
}
await inter.message.delete()
await channel.edit(overwrites=overwrites, name=f"closed-{channel.name[7:]}")
await channel.send(embed=embed, view=buttons)
elif inter.component.custom_id == "deleteChannelTicket":
path = Path("guilds/guilds.json")
ticketData = Path("tempFiles/ticket.json")
fromJsonData = json.loads(path.read_text(encoding="utf-8"))
toJsonData = json.loads(ticketData.read_text(encoding="utf-8"))
guild = bot.get_guild(inter.guild.id)
member = await guild.fetch_member(int(toJsonData["ticket"][f"{inter.guild.id}"][f"{inter.channel.id}"]["channel_owner"].replace('<@', '').replace('>', '')))
channel = bot.get_channel(int(fromJsonData["guilds"][f"{inter.guild_id}"]["transcript_channel"]))
transcript = await chat_exporter.export(
inter.channel,
bot=bot,
)
embed = disnake.Embed(title='**Aoyo ticket system**', colour=disnake.Color.green())
embed.add_field(name="Создатель", value=member.mention)
embed.add_field(name="Название канала", value=toJsonData["ticket"][f"{inter.guild.id}"][f"{inter.channel.id}"]["channel_name"], inline=False)
embed.add_field(name="Причина открытия", value=toJsonData["ticket"][f"{inter.guild.id}"][f"{inter.channel.id}"]["panel"], inline=True)
embed.set_image('https://media.discordapp.net/attachments/876280751488909332/979778066417070151/Frame_280.png?width=1440&height=4')
transcript_file = disnake.File(
io.BytesIO(transcript.encode()),
filename=f"transcript-{inter.channel.name}.html",
)
await bot.get_channel(int(fromJsonData["guilds"][f"{inter.guild.id}"]["transcript_channel"])).send(f"**Сохранен и отправлен {inter.channel.name}**",file=transcript_file)
embed = disnake.Embed(title='**Aoyo ticket system**', description='Канал удалится в течении 10 секунд.', colour=disnake.Color.purple())
await inter.message.edit(view=None)
await inter.response.send_message(embed=embed)
await sleep(9)
await bot.get_channel(inter.channel.id).delete(reason=f'Deleted by {inter.author.id}')
del toJsonData["ticket"][f"{inter.guild.id}"][f"{inter.channel.id}"]
ticketData.write_text(json.dumps(toJsonData, indent=3), encoding="utf-8", newline="\n")
# report
elif inter.component.custom_id == "reportAccept":
member = await bot.get_guild(inter.guild.id).fetch_member(int(inter.message.embeds[0].footer.text))
await member.send(embed=disnake.Embed(title="Aoyo REPORT", description=f"Ваш репорт был принят и рассмотрен модератором {inter.author.mention}", color=0x00ff00,timestamp=datetime.datetime.now()))
await inter.message.edit(components=[
disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="reportAccept", label="Принять", disabled=True),
disnake.ui.Button(label="Создать тикет", style=disnake.ButtonStyle.success, custom_id="reportCreateTicket", disabled=True),
disnake.ui.Button(label="Удалить репорт", style=disnake.ButtonStyle.danger, custom_id="deleteReport", disabled=True),
],)
await inter.message.edit(embed=inter.message.embeds[0].add_field(name="Репорт был принят!", value=f"Репорт принял {inter.author.mention}"))
await inter.response.send_message("Готово!", ephemeral=True)
elif inter.component.custom_id == "deleteReport":
await inter.response.send_message("Готово!", ephemeral=True)
await inter.message.edit(components=[
disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="reportAccept", label="Принять", disabled=True),
disnake.ui.Button(label="Создать тикет", style=disnake.ButtonStyle.success, custom_id="reportCreateTicket", disabled=True),
disnake.ui.Button(label="Удалить репорт", style=disnake.ButtonStyle.danger, custom_id="deleteReport", disabled=True),
],)
else:
await inter.response.send_message('Ошибка!', ephemeral=True)
def setup(bot):
bot.add_cog(buttons(bot))

47
cogs/court.py Normal file
View File

@@ -0,0 +1,47 @@
from handlers import bot
from disnake.ext import commands
import disnake
class courtCogs(commands.Cog):
def __init__(self, bot: disnake.Client):
self.bot = bot
@commands.slash_command(name="court")
@commands.has_permissions(administrator=True)
async def court(self, inter):
embed = disnake.Embed(title="**Города, где проходил суд**")
embed.add_field(name=" Селестия", value="> **Расположение**: -1050 -500 \n > **Количество проведенных судов**: (3)", inline=False)
embed.add_field(name=" South Point", value="> **Расположение**: -444 727 \n > **Количество проведенных судов**: (3)", inline=False)
embed.set_footer(text="Города добавляются через кнопки ниже. За пренебрежение командами следует наказание!")
view = disnake.ui.View()
view.add_item(disnake.ui.Button(style=disnake.ButtonStyle.blurple, label="Добавить город", custom_id="addSity"))
view.add_item(disnake.ui.Button(style=disnake.ButtonStyle.blurple, label="Провести суд", custom_id="addCourt"))
await inter.response.send_message(embed=embed, view=view)
@commands.Cog.listener("on_button_click")
async def on_button_click_court(self, inter: disnake.MessageInteraction):
if inter.component.custom_id == "addSity":
await inter.response.send_modal(title="Добавить город", custom_id="addSityModal", components=[
disnake.ui.TextInput(
label="Название города",
custom_id="sityName",
style=disnake.TextInputStyle.short,
),
disnake.ui.TextInput(
label="Координаты города",
custom_id="sityCoordinates",
style=disnake.TextInputStyle.short,
)])
if inter.component.custom_id == "addCourt":
await inter.response.send_modal(title="Провести суд", custom_id="addCourtModal", components=[
disnake.ui.TextInput(
label="Название города",
custom_id="sityName",
style=disnake.TextInputStyle.short,
)])
def setup(bot):
bot.add_cog(courtCogs(bot))

70
cogs/customModals.py Normal file
View File

@@ -0,0 +1,70 @@
from handlers import *
from disnake.ext import *
from disnake import *
import disnake
from pathlib import Path
import pyspw
import json
class customModals(commands.Cog):
def __init__(self, bot):
self.bot = bot
rootLogger.info(f"{__class__.__name__} подключен!")
@commands.slash_command(
name=Localised("createmodal", key="CREATE_MODAL_NAME"),
description=Localised("Create your`s own modal`s window.", key="CREATE_MODAL_DESC")
)
@commands.has_permissions(administrator=True)
async def createCustomModals(inter, channel: disnake.TextChannel, text_in_message: str, first_label: str, second_label: str, third_label: str, fourth_label: str=Option("fourth_label"), fifth_label: str=Option("fifth_label")):
"""Creation of your own windows (profiles)
Args:
channel (disnake.TextChannel): This is required to transfer the channel where the message will go about the application
text_in_message (str): This requires to transmit the text that will be above the application button (questionnaire/modal)
first_label (str): Enter here what you want to see in the first line of the questionnaire (tests are welcome)
second_label (str): Enter here what you want to see in the second line of the questionnaire (tests are welcome)
third_label (str): Enter here what you want to see in the third line of the questionnaire (tests are welcome)
fourth_label (str, optional): Enter here what you want to see in the fourth line of the questionnaire (tests are welcome)
fifth_label (str, optional): Enter here what you want to see in the fifth line of the questionnaire (tests are welcome)
"""
embed = disnake.Embed(title="**Aoyo Modal SYSTEM**")
embed.add_field(name="Нажмите на кнопку нижу для подачи заявки!", value=f"{text_in_message}")
buttons = disnake.ui.View().add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='buttonOnModal', label='Нажми на меня!'))
await inter.response.send_message("Готово!", ephemeral=True)
msg = await bot.get_channel(inter.channel.id).send(embed=embed, view=buttons)
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
arrayToSql = ["guild_id", "message_id", "channel_id", "first", "second", "third"]
dataToSql = [inter.guild.id, msg.id, channel.id, first_label, second_label, third_label]
newData = {
"channel": channel.id,
0: first_label,
1: second_label,
2: third_label,
"message_id": msg.id
}
if type(fourth_label) == str:
newData["3"] = fourth_label
arrayToSql.append("fourth")
dataToSql.append(fourth_label)
if type(fifth_label) == str:
newData["4"] = fifth_label
arrayToSql.append("fifths")
dataToSql.append(fifth_label)
print(SQL().createTable("modals"))
print(SQL().insertData(arrayToSql, dataToSql, "modals"))
if f"modals" not in data["guilds"][f"{inter.guild.id}"]:
data["guilds"][f"{inter.guild.id}"]["modals"] = {}
if f"{inter.channel.id}" not in data["guilds"][f"{inter.guild.id}"]["modals"]:
data["guilds"][f"{inter.guild.id}"]["modals"][f"{inter.channel.id}"] = {}
data["guilds"][f"{inter.guild.id}"]["modals"][f"{inter.channel.id}"][f"{msg.id}"] = newData
path.write_text(json.dumps(data, indent=6), encoding="utf-8", newline="\n")
def setup(bot):
bot.add_cog(customModals(bot))

166
cogs/modals.py Normal file
View File

@@ -0,0 +1,166 @@
# modals.py
from handlers import logger, bot, api_id, api_token
import disnake
from pathlib import Path
import json
from disnake.ext import commands
import pyspw
import sqlite3
import psycopg2
from handlers import execute
class modals(commands.Cog):
def __init__(self, bot: disnake.Client):
self.bot = bot
logger.info(f"Модуль {self.__class__.__name__} включен!")
@commands.Cog.listener("on_modal_submit")
async def on_modal_submit(self, inter: disnake.ModalInteraction):
await inter.response.send_message(f"{inter.custom_id}", ephemeral=True)
if inter.custom_id in ["changeNamePrivateRoom", "newUsersLimit"]:
path = Path("tempFiles/voiceTempFile.json")
data = json.loads(path.read_text(encoding="utf-8"))
if (
int(data["voice_channels"][f"{inter.channel.id}"]["channel_owner"])
== inter.author.id
):
path = Path("tempFiles/voiceName.json")
data = json.loads(path.read_text(encoding="utf-8"))
for key, value in inter.text_values.items():
if inter.custom_id == "changeNamePrivateRoom":
data[f"{inter.author.id}"] = {
"chat_name": f"{value[:1024]}",
"channel_id": f"{inter.channel.id}",
}
path.write_text(
json.dumps(data, indent=7), encoding="utf-8", newline="\n"
)
await self.bot.get_channel(inter.channel_id).edit(name=value[:1024])
else:
await self.bot.get_channel(inter.channel_id).edit(
user_limit=int(value[:1024])
)
await inter.response.send_message("Готово!", ephemeral=True)
else:
await inter.response.send_message(
"Вы не создатель канала!", ephemeral=True
)
elif inter.custom_id in ["customModal", "customModal-api", "interpol", "interpol-api"]:
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
embed = disnake.Embed(
description=f"{inter.author.mention}", colour=inter.author.colour
)
for key, value in inter.text_values.items():
embed.add_field(
name=key.capitalize(),
value=value[:1024],
inline=False,
)
embed.set_image(url=inter.author.avatar.url if inter.author.avatar else None)
if inter.custom_id in ["customModal-api", "interpol-api"]:
api = (
pyspw.SpApi(card_id=api_id, card_token=api_token)
.get_user(inter.author.id)
.nickname
)
embed.set_footer(text=f"Игрок подтвержден! Никнейм: {api}")
if inter.custom_id in ["interpol-api", "interpol"]:
embed.set_footer(text=f"{inter.channel.id}")
await self.bot.get_channel(
data["guilds"][f"{inter.guild.id}"]["modals"][f"{inter.channel.id}"]["channel"]).send(
f"{inter.author.mention}",
embed=embed,
components=[
disnake.ui.Button(
label="Принять",
style=disnake.ButtonStyle.success,
custom_id="acceptInterpol",
),
disnake.ui.Button(
label="Отклонить",
style=disnake.ButtonStyle.danger,
custom_id="declineInterpol",
),
disnake.ui.Button(
label="Создать тикет",
style=disnake.ButtonStyle.blurple,
custom_id="createInterpolTicket",
),
],
)
else:
await self.bot.get_channel(
data["guilds"][f"{inter.guild.id}"]["modals"][f"{inter.channel.id}"][
f"{inter.message.id}"
]["channel"]
).send(f"{inter.author.mention}", embed=embed)
await inter.response.send_message("Готово!", ephemeral=True)
elif inter.custom_id in ["addCourtModal", "addSityModal"]:
modal_inter = inter
if inter.custom_id == "addCourtModal":
print("no")
sityName = "Unbound"
for key, values in modal_inter.text_values.items():
sityName = values
i = -1
embed = inter.message.embeds[0]
fieldFromEmbed = None
for field in embed.fields:
i = i + 1
if field.name == sityName:
fieldFromEmbed = field
break
if not fieldFromEmbed:
await modal_inter.response.send_message("Вы указали неправильный город", ephemeral=True)
return False
symbol = (list(fieldFromEmbed.value)[-2])
embed = inter.message.embeds[0]
embed.set_field_at(i, name=sityName, value=fieldFromEmbed.value.replace(f"({symbol})", f"({str(int(symbol)+1)})"), inline=False)
await modal_inter.response.send_message("Готово!", ephemeral=True)
await inter.message.edit(embed=embed)
else:
await modal_inter.response.send_message("Готово!", ephemeral=True)
sityName = "Unbound"
sityCoordinates = "Unbound"
for key, values in modal_inter.text_values.items():
if key == "sityName":
sityName = values
elif key == "sityCoordinates":
sityCoordinates = values
embed = inter.message.embeds[0]
embed.add_field(name=sityName, value=f"> **Расположение**: {sityCoordinates} \n > **Количество проведенных судов**: (0)", inline=False)
await inter.message.edit(embed=embed)
elif inter.custom_id == "addFarmModal":
farmName = "Unbound"
farmCoordinates = "Unbound"
farmType = "Unbound"
sityName = "Unbound"
for key, values in inter.text_values.items():
if key == "farmName":
farmName = values
elif key == "farmCoordinates":
farmCoordinates = values
elif key == "farmType":
farmType = values
elif key == "sityName":
sityName = values
if ";" in farmName or ";" in farmCoordinates or ";" in farmType or ";" in sityName:
await inter.response.send_message("SQL инъекции не работает, сын шалавы", ephemeral=True)
await (await inter.guild.fetch_member(945317832290336798)).send(f"Сын шлюхи {inter.author.mention} попытался использовать sql-инъекцию в {inter.channel.mention}")
return
if inter.message.embeds[0].title == "**Фермы**":
execute("INSERT INTO farms VALUES ({}, {}, {}, {}, {})".format(f'"{farmName}"', f'"{farmCoordinates}"', f'"{farmType}"', f'"{sityName}"', inter.author.id))
else:
execute("INSERT INTO private_farms VALUES ({}, {}, {}, {}, {})".format(f'"{farmName}"', f'"{farmCoordinates}"', f'"{farmType}"', f'"{sityName}"', inter.author.id))
embed = inter.message.embeds[0]
embed.add_field(name=sityName, value=f"> **Название фермы**: {farmName} \n > **Расположение**: {farmCoordinates} \n > **Тип фермы**: {farmType}", inline=False)
await inter.message.edit(embed=embed)
await inter.response.send_message("Готово!", ephemeral=True)
def setup(bot):
bot.add_cog(modals(bot))

328
cogs/moderation.py Normal file
View File

@@ -0,0 +1,328 @@
import asyncio
import datetime as dt
import json
import os
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Optional, Union
import disnake
from disnake import Localized, OptionChoice
from disnake.ext import commands, tasks
from handlers import bot, now, takeSettings
from log import rootLogger
class common:
def __init__(self,
bot,
user_id: Optional[int] = None,
guild_id: Optional[int] = None):
"""Common functions
Args:
user_id (Optional[int], optional): _description_. Defaults to None.
guild_id (Optional[int], optional): _description_. Defaults to None.
"""
self.bot = bot
self.path = Path("mute.json")
self.guild_id = guild_id if guild_id is not None else None
self.user_id = user_id if user_id is not None else None
self.role = None
async def embed_message(self, end_time: str, time: int, reason: str, muted: int, file: Optional[str] = None):
guild = bot.get_guild(self.guild_id)
member = await guild.fetch_member(muted)
channel = self.bot.get_channel(int(takeSettings(self.guild_id, "mute_channel")))
emb = disnake.Embed(title=f"**System - Mute**", color=disnake.Color.purple(), timestamp=datetime.now())
emb.add_field(name="**Выдал:**", value=f"<@{self.user_id}>", inline=True)
emb.add_field(name="**Нарушитель:**", value=f"<@{muted}>", inline=True)
emb.add_field(name="**Причина:**", value=reason, inline=False)
if file != None:
emb.set_image(file)
if end_time in ["м", "m"]:
emb.add_field(name="**Длительность:**", value="{} минут()".format(time))
timesdelta = timedelta(minutes=float(time))
elif end_time in ["ч", "h"]:
emb.add_field(name="**Длительность:**", value="{} час(ов)".format(time))
timesdelta = timedelta(hours=float(time))
elif end_time in ["д", "d"]:
emb.add_field(name="**Длительность:**", value="{} день(ей)".format(time))
timesdelta = timedelta(days=float(time))
local_time = ((datetime.now() + timesdelta)
.astimezone()
.strftime("%d/%m/%Y %H:%M")
)
path = Path("mute.json")
data = json.loads(path.read_text(encoding="utf-8"))
data["mutes"][f"{local_time}"] = {f"{member.id}": {"user": f"{member.id}", "guild": f"{self.guild_id}"}}
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
await channel.send(embed=emb)
emb.remove_field(index=0)
emb.add_field(name="**Сервер:**", value=guild.name, inline=True)
await member.send(embed=emb)
def checkIsInMuted(self):
"""Проверка на наличие в базе мутов игрока
Args:
user (int): айдишечка пользователя
Returns:
bool: возвращается результат
"""
userData = json.loads(self.path.read_text(encoding="utf-8"))
for key in userData["mutes"]:
for data in userData["mutes"][key]:
return int(self.user_id) == int(userData["mutes"][key][data]['user'])
def new_DB(self):
"""Create db
Args:
guild_id (int): guild`s id for db
member (disnake.Member): member for data into db
"""
if not os.path.isfile(f"users/users_{self.guild_id}.json"):
with open(f"users/users_{self.guild_id}.json", "a") as file:
writeinfiledata = {
f"{self.guild_id}": {
f"{self.user_id}": {
"userID": f"{self.user_id}",
"warnCounter": "0",
"muteCounter": "1",
"userMention": f"<@{self.user_id}>",
"guild": f"{self.guild_id}",
}
}
}
json.dump(writeinfiledata, file)
file.close()
path = Path(f"users/users_{self.guild_id}.json")
userData = json.loads(path.read_text(encoding="utf-8"))
if f"{self.user_id}" not in userData[f"{self.guild_id}"]:
newUserData = {
"userID": f"{self.user_id}",
"warnCounter": "0",
"muteCounter": "1",
"userMention": f"<@{self.user_id}>",
"guild": f"{self.guild_id}",
}
userData[f"{self.guild_id}"]["muteCounter"] = newUserData
else:
userData[f"{self.guild_id}"]["muteCounter"] = +1
path.write_text(json.dumps(userData, indent=7), encoding="utf-8", newline="\n")
def deleteMute(self):
"""Удаление мута из базы данных
Args:
user (int): Айди пользователя
"""
userData = json.loads(self.path.read_text(encoding="utf-8"))
for key in userData["mutes"]:
for data in userData["mutes"][key]:
if data == self.user_id:
del userData["mutes"][key]
self.path.write_text(
json.dumps(userData, indent=4, ensure_ascii=False),
encoding="utf-8",
newline="\n",
)
return
def mute(self): return int(takeSettings(self.guild_id, "mute_role"))
def moderator(self): return int(takeSettings(self.guild_id, "moderation_role"))
async def issuedRole(self, types):
"""Выдача роли в отдельной функции для выдачи роли
Args:
guild_id (int): _description_
user_id (int): _description_
"""
guild: disnake.Guild = self.bot.get_guild(int(self.guild_id))
member: disnake.Member = await guild.fetch_member(int(self.user_id))
return bool(await member.add_roles(guild.get_role(types(self))))
async def removeRole(self, type: str):
"""Забирать роли для оптимизации кода
Args:
guild_id (int): Передавать guild id для забирания роли
user_id (int): Передавать user id для забирания роли
type (str): Передавать вид роли для выполнения функции
"""
guild: disnake.Guild = self.bot.get_guild(int(self.guild_id))
if type == "mute":
role: disnake.Role = guild.get_role((takeSettings(self.guild.id, "mute_role")))
member: disnake.Member = await guild.fetch_member(int(self.user_id))
await member.remove_roles(role)
class moderationCommands(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.path = Path("mute.json")
rootLogger.info("Модуль {} Включен".format(self.__class__.__name__))
async def preMuteFunc(self, user: int, guild: int):
"""Передача данных для полной работы с всеми требуемыми функциями
Args:
user (int): _description_
guild (int): _description_
Returns:
_type_: _description_
"""
common(self.bot, user_id=user, guild_id=guild).new_DB()
if common(self.bot, user_id=user).checkIsInMuted():
common(self.bot, user_id=user).deleteMute()
await common(self.bot, user_id=user, guild_id=guild).issuedRole(common.mute)
@commands.slash_command(name=Localized("clear", key="CLEAR_NAME"), description=Localized("Clear message in current channel", key="CLEAR_DESC"))
@commands.has_permissions(manage_messages=True)
async def clear(inter, amount: int):
await inter.response.send_message("Выполняется!", ephemeral=True)
channel = bot.get_channel(inter.channel.id)
await channel.purge(limit=amount + 1)
@commands.user_command(name=Localized("Mute", key="APP_MUTE_NAME") )
@commands.has_permissions(manage_messages=True)
async def muteUserByApplication(self, inter: disnake.ApplicationCommandInteraction, member: disnake.Member):
await inter.response.send_modal(
title='Mute',
custom_id='muteByApp',
components=[
disnake.ui.TextInput(
label="Время мута",
placeholder='2h',
custom_id='muteTime',
style=disnake.TextInputStyle.short,
max_length=3,
),
disnake.ui.TextInput(
label="Причина",
placeholder='Флуд',
custom_id='muteReason',
style=disnake.TextInputStyle.short,
),
],
)
try:
def check(m):
return m.author == inter.author and m.channel == inter.channel
modal_inter: disnake.ModalInteraction = await self.bot.wait_for(
event="modal_submit",
check=check,
timeout=30.0,
)
await modal_inter.response.send_message('Готово!', ephemeral=True)
amount = modal_inter.text_values['muteTime']
reason = modal_inter.text_values['muteReason']
await self.preMuteFunc(member.id, inter.guild.id)
await common(bot, inter.author.id, inter.guild.id).embed_message(end_time = amount[-1:], time = amount[:-1], reason = reason, muted=member.id)
except asyncio.TimeoutError:
return
@commands.slash_command(name="embed", description=Localized("Create Embedded Message", key="CREATE_EMBED_DESC"))
@commands.has_permissions(administrator=True)
async def embed_message(self, inter, title: str, description: str, file: Optional[disnake.Attachment] = None):
emb = disnake.Embed(title=title, description=f"{description}", color=disnake.Color.purple())
# emb.add_field(name=field_name, value=field_value, inline=False)
if file != None: emb.set_image(file.url)
await inter.response.send_message("Готово!", ephemeral=True)
await self.bot.get_channel(inter.channel.id).send(embed=emb)
@commands.slash_command(name=Localized("mute", key="MUTE_NAME"), description=Localized("Mute user", key="MUTE_DESC"))
@commands.has_permissions(manage_messages=True)
async def add(self, inter, member: disnake.Member, amount: str, reason: str, file: disnake.Attachment):
await self.preMuteFunc(member.id, inter.guild.id)
await common(bot, inter.author.id, inter.guild.id).embed_message(end_time = amount[-1:], time = amount[:-1], reason = reason, muted=member.id, file= file.url)
await inter.response.send_message("Готово!", ephemeral=True)
@commands.slash_command(
name=Localized("enableslowmode", key="ENABLEWLOWMODE_NAME"), description=Localized("Enable or disable slowmode in this channel", key="ENABLEWLOWMODE_DESC")
)
@commands.has_permissions(kick_members=True)
async def enableslowmode(inter, amount: int, time: str = commands.Param(
choices=[
OptionChoice("minute", "m"),
OptionChoice("second", "s"),
]
)
):
await inter.response.send_message("Готово!", ephemeral=True)
if time == "s":
await inter.channel.edit(slowmode_delay=amount)
elif time == "m":
await inter.channel.edit(slowmode_delay=(amount * 60))
else:
await inter.response.send_message(
"Неправильно указано время, или иное", ephemeral=True
)
@commands.slash_command(name=Localized("unmute", key="UNMUTE_NAME"), description=Localized("Unmute user", key="UNMUTE_DESC"))
@commands.has_permissions(kick_members=True)
async def unmute(self, inter, user: disnake.Member):
role = self.bot.get_guild(inter.guild.id).get_role(
takeSettings(inter.guild.id, "mute_role")
)
if role in user.roles:
await inter.response.send_message("Готово!", ephemeral=True)
await common(bot, user.id, inter.guild.id).removeRole("mute_role")
else:
await inter.response.send("Неправильный аргумент, или пользователь не замучен", ephemeral=True)
@commands.slash_command(name=Localized("changenick", key='CHANGENICK_NAME'), description=Localized("Changes nickname ", key="CHANGENICK_DESC"))
async def changenick(self, inter, member: disnake.Member, changednick):
path= Path(f"users/users_{inter.guild.id}.json")
common(bot, member.id, inter.guild.id).new_DB()
await inter.response.send_message("Готово!", ephemeral=True)
readedData = json.loads(path.read_text(encoding="utf-8"))
warnCounter = int(
readedData[f"{inter.guild.id}"][f"{member.id}"]["warnCounter"]
)
e = disnake.Embed(
description="Aoyo.Moderation SYSTEM", color=disnake.Color.purple()
)
e.add_field(name="**Сменил:**", value=inter.author.mention)
e.add_field(name="**Старый ник:**", value=member.name)
e.add_field(name="**Новый ник:**", value=changednick)
e.add_field(name="**Количество смененных ников:**", value=f"{warnCounter+1}")
readedData[f"{inter.guild_id}"][f"{member.id}"]["warnCounter"] = +1
path.write_text(
json.dumps(readedData, indent=6), encoding="utf-8", newline="\n"
)
await member.edit(nick=changednick)
await self.bot.get_channel(
int(takeSettings(inter.guild_id, "mute_channel"))
).send(embed=e)
e.remove_field(index=0)
e.add_field(name="**Сервер:**", value=inter.guild.name, inline=True)
await member.send(embed=e)
def setup(bot):
bot.add_cog(moderationCommands(bot))

172
cogs/multiguild.py Normal file
View File

@@ -0,0 +1,172 @@
from disnake import *
from disnake.ext import commands
from handlers import *
from log import rootLogger
import json
from dislash import Option
from pathlib import Path
import disnake
from validators import url
class multiGuildSettings(commands.Cog):
def __init__(self, bot):
self.bot = bot
rootLogger.info("Модуль {} подключен!".format(self.__class__.__name__))
@commands.slash_command(name=Localized('settings', key="SETTINGS"))
@commands.has_permissions(administrator=True)
async def settings(self, inter):
pass
@settings.sub_command(
name=Localized("setup", key="SETUP_NAME"),
description=Localized("Setting a bot on the server.", key="SETUP_DESC"),)
@commands.has_permissions(administrator=True)
async def allsettings(inter,
mute_role: disnake.Role,
mute_channel: disnake.TextChannel,
moderation_role: disnake.Role,
on_join_role: disnake.Role,
report_channel: disnake.TextChannel,
transcript_channel: disnake.TextChannel,
):
writedData={
"mute_role": f"{mute_role.id}",
"mute_channel": f"{mute_channel.id}",
"on_join_role": f"{on_join_role.id}",
"moderation_role": f"{moderation_role.id}",
"report_channel": f"{report_channel.id}",
}
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if f"{inter.guild.id}" not in data["guilds"]:
data["guilds"][f"{inter.guild.id}"] = {}
data["guilds"][f"{inter.guild.id}"]["mute_role"] = mute_role.id
data["guilds"][f"{inter.guild.id}"]["mute_channel"]= mute_channel.id
data["guilds"][f"{inter.guild.id}"]["on_join_role"] = on_join_role.id
data["guilds"][f"{inter.guild.id}"]["report_channel"] = report_channel.id
data["guilds"][f"{inter.guild.id}"]["moderation_role"] = moderation_role.id
data["guilds"][f"{inter.guild.id}"]["transcript_channel"] = transcript_channel.id
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
else:
data["guilds"][f"{inter.guild.id}"]["mute_role"] = mute_role.id
data["guilds"][f"{inter.guild.id}"]["mute_channel"]= mute_channel.id
data["guilds"][f"{inter.guild.id}"]["on_join_role"] = on_join_role.id
data["guilds"][f"{inter.guild.id}"]["report_channel"] = report_channel.id
data["guilds"][f"{inter.guild.id}"]["moderation_role"] = moderation_role.id
data["guilds"][f"{inter.guild.id}"]["transcript_channel"] = transcript_channel.id
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
await inter.response.send_message("Готово! Ваш сервер сохранен в настройках бота!", ephemeral=True)
@settings.sub_command(name=Localized('guestroom', key="GUESTROOM_NAME"), description=Localized('Settings of the Entrance of the player', key="GUESTROOM_DESC"))
@commands.has_permissions(administrator=True)
async def guestroom(inter,
guest_room: disnake.TextChannel=Option("guest_room",description="Укажите канал, в который будет отправляться сообщение о входе пользователя", required=True),
image: str=Option("image", description="Укажите ссылку на фото или гиф файл, который будет отправляться вместе с сообщением о прибытии!", required=True),
text: str=Option("text", description="Укажите текст, который должен присылаться вместе с сообщением о прибытии пользователя", required=True),
):
if not url(image):
url = None
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
data["guilds"][f"{inter.guild.id}"]["guest_room"] = guest_room.id
data["guilds"][f"{inter.guild.id}"]["image_url"] = f"{image}"
data["guilds"][f"{inter.guild.id}"]["guest_text"] = f"{text}"
if "server" not in data:
data["guilds"][f"{inter.guild.id}"]["server"] = "None"
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
await inter.response.send_message("Готово!", ephemeral=True)
@settings.sub_command(
name=Localized('autobrench', key='AUTOBRENCH_NAME'),
description=Localized("Automatic creation of branches in the channels", key="AUTOBRENCH_DESC")
)
@commands.has_permissions(administrator=True)
async def autobrench(inter: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel):
path = Path("guilds/guilds.json")
jsonData = json.loads(path.read_text(encoding="utf-8"))
if f"autobrench" not in jsonData["guilds"][f"{inter.guild.id}"]:
jsonData["guilds"][f"{inter.guild.id}"]["autobrench"] = {}
path.write_text(json.dumps(jsonData, indent=4), encoding="utf-8", newline="\n")
jsonData = json.loads(path.read_text(encoding="utf-8"))
jsonData["guilds"][f"{inter.guild.id}"]["autobrench"][f"{channel.id}"] = channel.id
path.write_text(json.dumps(jsonData, indent=4), encoding="utf-8", newline="\n")
await inter.response.send_message("Автоматическое создание веток настроено!", ephemeral=True)
@settings.sub_command(
name=Localized("autoreaction", key="AUTOREACTION_NAME"),
description=Localized("Autoreaction setting up", key="AUTOREACTION_DESC")
)
@commands.has_permissions(administrator=True)
async def autoreaction(inter: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel, reaction1: disnake.Emoji, reaction2: disnake.Emoji=Option("reaction2")):
path = Path("guilds/guilds.json")
jsonData = json.loads(path.read_text(encoding="utf-8"))
if f"autoreaction" not in jsonData["guilds"][f"{inter.guild.id}"]:
jsonData["guilds"][f"{inter.guild.id}"]["autoreaction"] = {}
path.write_text(json.dumps(jsonData, indent=4), encoding="utf-8", newline="\n")
jsonData = json.loads(path.read_text(encoding="utf-8"))
try:
try:
second_react = reaction2.id
except:
second_react = "None"
jsonData["guilds"][f"{inter.guild.id}"]["autoreaction"][f"{channel.id}"] = {
"reaction1": reaction1.id,
"reaction2": second_react
}
path.write_text(json.dumps(jsonData, indent=4), encoding="utf-8", newline="\n")
await inter.response.send_message("Автореакция установлена", ephemeral=True)
except Exception as e:
await inter.response.send_message(f"Эмодзи не найдено. Попробуйте использовать эмодзи с этого сервера", ephemeral=True)
@settings.sub_command(
name="auth",
description=Localized("User authentication, if it is in the server database", key="AUTH_DESC")
)
@commands.has_permissions(administrator=True)
async def authUser(inter, gived_role: disnake.Role, token_id: str, card_id: str):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
data["guilds"][f"{inter.guild.id}"]["server"] = {
"role": f"{gived_role.id}",
"token": token_id,
"card": card_id
}
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
await inter.response.send_message('Готово!', ephemeral=True)
@settings.sub_command(
name=Localized("autovoice", key="AUTOVOICE_NAME"),
description="Automatic creation of voice channels (if the user connects to [+] create)"
)
@commands.has_permissions(administrator=True)
async def autovoice(inter, answer: str = commands.Param(choices=[
disnake.OptionChoice(Localized("Turn ON", key="AUTOVOICE_ON"), "on"),
disnake.OptionChoice(Localized("Turn OFF", key="AUTOVOICE_OFF"), "off"),
]
)):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if answer == "on": answer = True
else: answer = False
data["guilds"][f"{inter.guild.id}"]["autovoice"] = f"{answer}"
path.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
await inter.response.send_message('Готово!', ephemeral=True)
def setup(bot):
bot.add_cog(multiGuildSettings(bot))

36
cogs/saveChannels.py Normal file
View File

@@ -0,0 +1,36 @@
from disnake.ext import commands
import disnake
import chat_exporter
from typing import Optional
import io
class saveChannel(commands.Cog):
def __init__(self, bot):
self.bot = bot
@commands.slash_command(name=disnake.Localized('save-channel', key='SAVECHANNEL_NAME'),
description=disnake.Localized('Saves channel data, and later sends them to a separate channel', key="SAVECHANNEL_DESC"))
@commands.has_permissions(administrator=True)
async def save_channel(self, inter, chat: Optional[disnake.TextChannel]):
if type(chat) == disnake.TextChannel:
channel = chat
else:
channel = inter.channel
transcript = await chat_exporter.export(
channel,
bot=self.bot,
)
if transcript is None:
return
transcript_file = disnake.File(
io.BytesIO(transcript.encode()),
filename=f"transcript-{inter.channel.name}.html",
)
await inter.send(file=transcript_file)
await inter.response.send_message("Готово!", ephemeral=True)
def setup(bot):
bot.add_cog(saveChannel(bot))

87
cogs/ticket.py Normal file
View File

@@ -0,0 +1,87 @@
from disnake.ext import commands
from disnake import *
from handlers import *
from log import *
import json
from dislash import Option
import disnake
from pathlib import Path
class ticket(commands.Cog):
def __init__(self,bot):
self.bot = bot
rootLogger.info(f"Модуль {self.__class__.__name__} подключен!")
@commands.slash_command(
name=Localized("ticket", key="TICKET_NAME"),
description=Localized("Creating a tick for your server! (With buttons)", key="TICKET_DESC"))
@commands.has_permissions(administrator=True)
async def createTicket(inter,
ticket_name: str,
ticket_description: str,
channel: disnake.TextChannel,
first_button_name: str,
first_button_role: disnake.Role,
channel_for_transcript: disnake.TextChannel,
second_button_name: str=Option("second_button_name", description="Укажите название второй кнопки"),
second_button_role: disnake.Role=Option("second_button_name", description="Укажите роль для второй кнопки"),
third_button_name: str=Option("third_button_name", description="Укажите название третьей кнопки"),
third_button_role: disnake.Role = Option("third_button_name", type=disnake.Role, description="Укажите роль для третьей кнопки") ):
"""
Give several cookies to a user
Parameters
----------
ticket_description: Description in create_ticket message
channel: Specify the channel through which the message will be sent to create tickets
first_button_name: First name of the button
first_button_role: The first role that will be pinged when the ticket is opened,
channel_for_transacript: The channel, where the message with transcript will be sent
"""
embed = disnake.Embed(title="**Ticket**", description=ticket_description, colour=disnake.Color.blue())
embed.set_image('https://media.discordapp.net/attachments/876280751488909332/979778066417070151/Frame_280.png?width=1440&height=4')
embed.set_footer(text='Aoyo ticket system by YaFlay',)
buttons = disnake.ui.View()
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id="firstTicket", label=first_button_name))
msg = await channel.send(embed=embed, view=buttons)
try: category = channel_for_transcript.category.id
except Exception: category = channel.category.id
try:
sec_role = second_button_role.id
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="secondTicket", label=second_button_name))
except Exception: sec_role = "None"
try:
third_role = third_button_role.id
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.green, custom_id="thirdTicket", label=third_button_name))
except Exception: third_role = "None"
writedData={
"channel": f"{channel_for_transcript.id}",
"category": f"{category}",
"message_id": f"{msg.id}",
"guild": f"{inter.guild_id}",
"first_role": f"{first_button_role.id}",
"second_role": f"{sec_role}",
"third_role": f"{third_role}"
}
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if f"{inter.guild.id}" not in data["guilds"]:
await inter.response.send_message("Вы не настроили сервер! сделайте это прямо сейчас при помощи команды /settings setup!")
return
elif "ticket" not in data["guilds"][f"{inter.guild_id}"]:
data["guilds"][f"{inter.guild_id}"]["ticket"] = {}
data["guilds"][f"{inter.guild_id}"]["ticket"][f"{channel.id}"] = {}
data["guilds"][f"{inter.guild_id}"]["ticket"][f"{channel.id}"][f"{msg.id}"] = (writedData)
path.write_text(json.dumps(data, indent=3), encoding="utf-8", newline="\n")
await inter.response.send_message('Готово!', ephemeral=True)
def setup(bot):
bot.add_cog(ticket(bot))

157
cogs/usersCommand.py Normal file
View File

@@ -0,0 +1,157 @@
from disnake.ext import commands
import disnake
from handlers import *
from log import *
import datetime
import json
import asyncio
class usersCommand(commands.Cog):
def __init__(self,bot):
self.bot = bot
rootLogger.info("Модуль {} подключен!".format(self.__class__.__name__))
@commands.user_command(name=disnake.Localized('Get avatar', key="GET_AVATAR"))
async def getAvatar(self, inter: disnake.ApplicationCommandInteraction, user: disnake.User):
embed = disnake.Embed(description=f"Аватарка пользователя {user.mention}")
embed.set_image(user.avatar.url)
await inter.response.send_message(inter.author.mention, embed=embed, ephemeral=True)
@commands.message_command(name=disnake.Localized("Report", key="REPORT"))
async def moderationReport(self, inter: disnake.ApplicationCommandInteraction, message: disnake.Message):
await inter.response.send_modal(
title="Репорты",
custom_id="reportModal",
components=[
disnake.ui.TextInput(
label="Комментарий к репорту",
placeholder='Меня оскорбили',
custom_id='comment',
style=disnake.TextInputStyle.short
)
],)
try:
def check(m):
return m.author == inter.author and m.channel == inter.channel
modal_inter: disnake.ModalInteraction = await self.bot.wait_for(
event="modal_submit",
check=check,
timeout=30.0,
)
valueFromFor = modal_inter.text_values['comment']
embed = disnake.Embed(
title=f"Подали репорт!",
description=f"Ссылка на сообщение: [Тык](https://discord.com/channels/{message.guild.id}/{message.channel.id}/{message.id})\nАвтор сообщения: {message.author.name}\nАвтор репорта: {inter.author.name}\nСообщение, на которое подали жалобу: {message.content}\nПричина жалобы: {valueFromFor}",
color=0x00ff00,
timestamp=datetime.datetime.now()
)
embed.set_image('https://media.discordapp.net/attachments/876280751488909332/979778066417070151/Frame_280.png?width=1440&height=4')
embed.set_thumbnail(url=message.author.avatar)
embed.set_footer(text=f"{inter.author.id}")
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
button = disnake.ui.View()
button.add_item(disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="reportAccept", label="Принять"))
button.add_item(disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id="reportCreateTicket", label="Создать тикет"))
button.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id="deleteReport", label="Удалить репорт"))
await self.bot.get_channel(int(data["guilds"][f"{message.guild.id}"]["report_channel"])).send(embed=embed, view=button)
await modal_inter.response.send_message("Вы удачно отправили репорт! Я отправил сообщение модерации.", ephemeral=True)
return
except asyncio.TimeoutError:
return
@commands.message_command(name=disnake.Localized("Change Field", key="CHANGEFIELD"))
@commands.has_permissions(administrator=True)
async def change_field(self, inter: disnake.ApplicationCommandInteraction, message: disnake.Message):
await inter.response.send_modal(
title="Смена строки",
custom_id="changeField",
components=[
disnake.ui.TextInput(
label="Номер строки(Если их одна, то напишите 0)",
placeholder='1',
custom_id='numberField',
style=disnake.TextInputStyle.short,
max_length=1,
),
disnake.ui.TextInput(
label="Новое значение",
placeholder='Меня зовут Кира Йошикаге',
custom_id='newField',
style=disnake.TextInputStyle.short,
),
],
)
try:
def check(m):
return m.author == inter.author and m.channel == inter.channel
modal_inter: disnake.ModalInteraction = await self.bot.wait_for(
event="modal_submit",
check=check,
timeout=30.0,
)
await modal_inter.response.send_message('Готово!', ephemeral=True)
numberOfField = int(modal_inter.text_values['numberField']) if int(modal_inter.text_values['numberField']) == 0 else int(modal_inter.text_values['numberField']) - 1
print(numberOfField)
newField = modal_inter.text_values['newField']
embed = message.embeds[0]
name = embed.fields[numberOfField].name
embed.remove_field(numberOfField)
embed.add_field(name=name, value=newField)
await message.edit(embed=embed)
except asyncio.TimeoutError:
return
@commands.slash_command(name=disnake.Localized('issue-role', key='ISSUE_ROLE_NAME'), description=disnake.Localized('Roaling by pressing the button', key="ISSUE_ROLE_DESC"))
@commands.has_permissions(administrator=True)
async def issueRole(self, inter, role1: disnake.Role, role2: disnake.Role, role3: disnake.Role):
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding='utf-8'))
embed = disnake.Embed(title='Выдача ролей', description=f'{role1.mention}\n{role2.mention}\n{role3.mention}', color=0x00ff00)
embed.set_image('https://media.discordapp.net/attachments/876280751488909332/979778066417070151/Frame_280.png?width=1440&height=4')
channel = bot.get_channel(inter.channel.id)
message_id = await channel.send(embed=embed,
components=[
disnake.ui.Button(label=role1.name, style=disnake.ButtonStyle.secondary, custom_id="role1"),
disnake.ui.Button(label=role2.name, style=disnake.ButtonStyle.secondary, custom_id="role2"),
disnake.ui.Button(label=role3.name, style=disnake.ButtonStyle.secondary, custom_id="role3"),
],
)
data["guilds"][f"{inter.guild.id}"]["issues"] = {
f"{message_id.id}":{
"role1": role1.id,
"role2": role2.id,
"role3": role3.id,
}}
path.write_text(json.dumps(data, indent=7), encoding='utf-8', newline='\n')
await inter.response.send_message('Готово!', ephemeral=True)
@commands.slash_command(
name='help',
description='Показать список команд')
async def help(inter):
embed = disnake.Embed(title="**Aoyo help**", color=0x00ff00)
embed.add_field(name="**!help**", value="Показать список команд", inline=False)
embed.add_field(name="!clear [кол-во]", value="Удаляет сообщения", inline=False)
embed.add_field(name="**/mute [пользователь] [время(1m, 1s)] [причина]**", value="Выдать мут", inline=False)
embed.add_field(name="**/unmute [пользователь]**", value="Размут пользователя", inline=False)
embed.add_field(name="**/changenick [пользователь] [ник]**", value="Изменить ник пользователя", inline=False)
embed.add_field(name="**/embed [название] [текст]**", value="Создать embed сообщение", inline=False)
embed.add_field(name="**/permmute [пользователь] [причина]**", value="Выдать мут навсегда", inline=False)
embed.add_field(name="**/settings setup [роль мута] [канал для мута] [модератор роль] [роль для нынезашедших] [канал для транскрипций тикета]**", value="Настройки сервера", inline=False)
embed.add_field(name="/ticket [название тикета] [описание тикета] [канал для тикета] [название первой кнопки] [пингующая роль первой кнопки] [и т.д.]", value="Создать тикет", inline=False)
embed.add_field(name="/settings autoreaction [канал] [реакция] [реакция]", value="Создать автореакцию", inline=False)
embed.add_field(name="/settings autobrench [канал]", value="Автосоздание веток в этом канале", inline=False)
embed.add_field(name="/deletechannel", value="Созвать собрание администрации для удаления канала", inline=False)
embed.add_field(name="/enableslowmode [время(1m, 1s)]", value="Включить медленный режим", inline=False)
await inter.response.send_message(embed=embed, ephemeral=True)
def setup(bot):
bot.add_cog(usersCommand(bot))

207
cogs/voiceBot.py Normal file
View File

@@ -0,0 +1,207 @@
import disnake
import yt_dlp # type: ignore
from disnake.ext import commands, tasks
import asyncio
from typing import Any, Dict, Optional
# Suppress noise about console usage from errors
yt_dlp.utils.bug_reports_message = lambda: ""
from yandex_music import ClientAsync, Client
import ytmusicapi
from handlers import logger
from pathlib import Path
import json
import os
type_to_name = {
'track': 'трек',
'artist': 'исполнитель',
'album': 'альбом',
'playlist': 'плейлист',
'video': 'видео',
'user': 'пользователь',
'podcast': 'подкаст',
'podcast_episode': 'эпизод подкаста',
}
yt = ytmusicapi.YTMusic()
ffmpeg_options = {'options': '-vn', 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'}
ytdl = yt_dlp.YoutubeDL({'outtmpl': '%(id)s.%(ext)s'})
class YTDLSource(disnake.PCMVolumeTransformer):
def __init__(self, source: disnake.AudioSource, *, data: Dict[str, Any], volume: float = 0.125):
super().__init__(source, volume)
self.title = data.get("title")
self.author = data.get("author")
self.source = data.get("source")
self.id = data.get("unicalID")
self.thumbnails: str = data.get("icon")
self.data = data
@classmethod
async def from_url(
cls, url, *, loop: Optional[asyncio.AbstractEventLoop] = None, stream: bool = True
):
player = None
if not "http" in url:
try:
url = f"https://youtube.com/watch?v={yt.search(url)[0]['videoId']}"
except Exception:
env = os.environ
client = await ClientAsync(env.get("YANDEX_TOKEN")).init()
func = (await client.search(url, nocorrect=False)).best
artists = str(func.result.artists_name()).replace("'", '').replace("[", '').replace("]", '')
logger.info(f"[yandex] Downloading {func.result.title}")
# func.result.download(f"music.mp3")
logger.info(f"[yandex] Downloaded...")
logger.info(f"[yandex] Openning ....")
try:
player = cls(disnake.FFmpegPCMAudio(await (await func.result.get_download_info_async())[0].get_direct_link_async(), **ffmpeg_options), data={'title': func.result.title, 'author': artists, 'source': "YandexMusic", 'fileName': f"{func.result.title}", 'type': "mp3", 'unicalID': f"https://music.yandex.ru/track/{func.result.id}", "icon": func.result.get_og_image_url()})
except Exception:
player = cls(disnake.FFmpegPCMAudio(f"music.mp3", **ffmpeg_options), data={'title': func.result.title, 'author': artists, 'source': "YandexMusic", 'fileName': f"{func.result.title}", 'type': "mp3", 'unicalID': f"https://music.yandex.ru/track/{func.result.id}", "icon": func.result.get_og_image_url()})
logger.info(f"[yandex] Playing {func.result.title}")
if not player:
loop = loop or asyncio.get_event_loop()
data: Any = await loop.run_in_executor(
None, lambda: ytdl.extract_info(url, download=False)
)
filename = data["formats"][5]["url"] if stream else ytdl.prepare_filename(data)
data["author"] = data["channel"]
data["source"] = "YouTube"
data["type"] = data["formats"][5]["audio_ext"]
data["unicalID"] = url
data["icon"] = data["thumbnails"][38]["url"]
data["fileName"] = filename
title = data.get("title")
audio_type = data["type"]
logger.info(f"[YouTube] Playing {title}")
logger.info(f"[Youtube] Audio type {audio_type}")
player = cls(disnake.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)
return player
class Music(commands.Cog):
def __init__(self, bot: commands.Bot):
self.bot = bot
self.queue = {"a": "a"}
def __channel(self, inter) -> disnake.VoiceProtocol | None:
for voiceProtocol in self.bot.voice_clients:
if voiceProtocol.guild == inter.guild:
return voiceProtocol
# @tasks.loop()
# async def on_Voice_state_loop(self):
# voice_state = self.bot.voice_clients
@commands.slash_command()
async def join(self, inter: disnake.ApplicationCommandInteraction, channel: Optional[disnake.VoiceChannel] = None):
"""Joins a voice channel"""
channel = inter.author.voice.channel if not channel else channel
if self.__channel(inter): await self.__channel(inter).disconnect()
await channel.connect()
await inter.response.send_message(f"Подключился к каналу {channel.mention}", ephemeral=True)
# @commands.slash_command()
# async def queue(self, inter, *args): pass
# @commands.slash_command(name="queue")
# async def add_to_queue(self, inter: disnake.ApplicationCommandInteraction, prompt_to_queue: str):
# try:
# await inter.response.defer()
# player = await YTDLSource.from_url(prompt_to_queue, loop=self.bot.loop, stream=True)
# try:
# if len(self.queue[inter.guild.id]) == 0:
# if self.__channel(inter): await self.__channel(inter).disconnect()
# self.start_playing(await self.ensure_voice(inter), player, inter.guild)
# await inter.send(f':mag_right: **Searching for** ``' + prompt_to_queue + '``\n<:youtube:763374159567781890> **Now Playing:** ``{}'.format(player.title) + "``")
# else:
# self.queue[len(self.queue[inter.guild.id])] = player
# await inter.send(f':mag_right: **Searching for** ``' + prompt_to_queue + '``\n<:youtube:763374159567781890> **Added to queue:** ``{}'.format(player.title) + "``")
# except KeyError:
# self.queue[inter.guild.id] = []
# if self.__channel(inter): await self.__channel(inter).disconnect()
# self.start_playing(await self.ensure_voice(inter), player, inter.guild)
# await inter.send(f':mag_right: **Searching for** ``' + prompt_to_queue + '``\n<:youtube:763374159567781890> **Now Playing:** ``{}'.format(player.title) + "``")
# except Exception as e:
# await inter.send(f"Somenthing went wrong - please try again later! ||{e}||")
# def start_playing(self, voice_client, player, guild:disnake.Guild):
# self.queue[guild.id].append(player)
# for i in self.queue[guild.id]:
# try:
# voice_client.play(i, after=lambda e: print('Player error: %s' % e) if e else None)
# except:
# pass
@commands.slash_command()
async def play(self, inter: disnake.ApplicationCommandInteraction, prompt: str):
"""Plays from a url (almost anything youtube_dl supports)"""
if self.__channel(inter): await self.__channel(inter).disconnect()
voiceState: disnake.VoiceClient = await self.ensure_voice(inter)
await inter.response.defer(with_message=True)
player = await YTDLSource.from_url(prompt, loop=self.bot.loop, stream=True)
embed = disnake.Embed(title="Вопроизведение музыки.", description=f"**Трек**: {player.title}\n **Автор**: {player.author}\n **Ссылка**: [Тык]({player.id})").set_footer(text=f"Источник: {player.source}").set_thumbnail(url=player.thumbnails)
await inter.send(embed=embed)
voiceState.play(
player, after=lambda e: logger.error(f"Error: {e}") if e else None
)
@commands.slash_command()
async def leave(self, inter: disnake.ApplicationCommandInteraction):
"""Stops and disconnects the bot from voice"""
await self.__channel(inter).disconnect()
await inter.response.send_message("Бот вышел из канала", ephemeral=True)
@commands.slash_command()
async def stop(self, inter: disnake.ApplicationCommandInteraction):
"""Paused music"""
await self.ensure_voice(inter)
await inter.response.send_message("Бот остановил воспроизведение", ephemeral=True)
@commands.slash_command()
async def pause(self, inter: disnake.ApplicationCommandInteraction):
"""Paused music"""
await self.ensure_voice(inter, 'pause')
await inter.response.send_message("Бот остановил воспроизведение", ephemeral=True)
@commands.slash_command()
async def resume(self, inter: disnake.ApplicationCommandInteraction):
"""Paused music"""
await self.ensure_voice(inter, 'resume')
await inter.response.send_message("Бот продолжил воспроизведение воспроизведение", ephemeral=True)
async def ensure_voice(self, inter, types:str = None):
if self.__channel(inter) == None:
if inter.author.voice:
return await inter.author.voice.channel.connect()
else:
await inter.send("You are not connected to a voice channel.", ephemeral=True)
raise commands.CommandError("Author not connected to a voice channel.")
elif types == "pause" and self.__channel(inter).is_playing():
self.__channel(inter).pause()
elif types == "resume" and not self.__channel(inter).is_playing():
self.__channel(inter).resume()
elif self.__channel(inter).is_playing():
self.__channel(inter).stop()
def setup(bot):
bot.add_cog(Music(bot))

81
cogs/voiceChannels.py Normal file
View File

@@ -0,0 +1,81 @@
from disnake.ext import *
import disnake
from pathlib import Path
from handlers import *
import json
from log import rootLogger
voiceChannelData = Path("tempFiles/voiceTempFile.json")
voiceChannelName = Path("tempFiles/voiceName.json")
class audioChannelAutomatization(commands.Cog):
def __init__(self, bot):
self.bot = bot
rootLogger.info(f'Модуль {self.__class__.__name__} включен!')
@bot.event
async def on_voice_state_update(member, before, after):
if after.channel and after.channel != before.channel and after.channel.name in ['[+] СОЗДАТЬ', '[+]СОЗДАТЬ']:
guild = bot.get_guild(member.guild.id)
category = disnake.utils.get(guild.categories, id=after.channel.category.id)
data = json.loads(voiceChannelName.read_text(encoding="utf-8"))
if f"{member.id}" in data:
channel = await guild.create_voice_channel(name=f'{data[f"{member.id}"]["chat_name"]}', category=category)
else:
channel = await guild.create_voice_channel(name=f'{member.name}`s voice channel', category=category)
await member.edit(voice_channel=channel)
data[f"{member.id}"]["channel_id"] = f"{channel.id}"
voiceChannelName.write_text(json.dumps(data, indent=7), "utf-8", newline='\n')
embeded = disnake.Embed(title="Пользователь присоединился к каналу", description=f"Пользователь: {member.mention}\n Канал: {after.channel.name}",timestamp=datetime.datetime.now(), color=0x00ff00)
embed = disnake.Embed(title = '**Управление приватными комнатами**',
description="""Вы можете изменить конфигурацию своей комнаты с помощью кнопок ниже.
**Переименовать приватную комнату:** ✏️
**Задать лимит участников приватной комнаты:**👥
**Закрыть/Открыть приватную комнату:**🔒
**Скрыть/Открыть приватную комнату:**👀
**Удалить канал(только для создателей канала):** \"Удалить канал\"""", colour=disnake.Colour.from_rgb(47, 49, 54))
buttons = disnake.ui.View()
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='renamePrivateRoom', emoji=''))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='setUsersLimit', emoji='👥'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='closePrivateRoom', emoji=f'🔒'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='hidePrivateRoom', emoji=f'👀'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.secondary, custom_id='kickUser', label='Кикнуть пользователя'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id='deleteChannel', label='Удалить канал'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.danger, custom_id='giveOwner', label='Передать права на канал'))
buttons.add_item(disnake.ui.Button(style=disnake.ButtonStyle.success, custom_id='takeOwner', label='Забрать права на канал'))
await bot.get_guild(member.guild.id).get_channel(channel.id).send(embed=embed, view=buttons)
writeData = {
'chat_name': f'{after.channel.name}',
'channel_owner': f'{member.id}',
'chat_id': f'{after.channel.id}',
}
data = json.loads(voiceChannelData.read_text(encoding="utf-8"))
data["voice_channels"][f'{after.channel.id}'] = writeData
voiceChannelData.write_text(json.dumps(data, indent=7), encoding="utf-8", newline="\n")
elif before.channel and after.channel != before.channel:
embeded = disnake.Embed(title="Пользователь покинул канал.", description=f"Пользователь: {member.mention}\n Канал: {before.channel.name}",timestamp=datetime.datetime.now(), color=disnake.Colour.from_rgb(186, 0, 6))
guild = bot.get_guild(member.guild.id)
data = json.loads(voiceChannelName.read_text(encoding="utf-8"))
for item in data:
if data[item]['channel_id'] == str(before.channel.id):
if before.channel.name == f'{member.name}`s voice channel' or before.channel.name == data[item]["chat_name"] and not len(before.channel.members):
try:
await before.channel.delete()
except Exception as e:
print(e)
else: pass
path = Path("guilds/guilds.json")
data = json.loads(path.read_text(encoding="utf-8"))
if data["guilds"][f"{member.guild.id}"]["logs"]:
embeded.set_thumbnail(url=member.avatar)
await bot.get_channel(data["guilds"][f"{member.guild.id}"]["logs"]).send(embed=embeded)
def setup(bot):
bot.add_cog(audioChannelAutomatization(bot))

6
guilds/guilds.json Normal file
View File

@@ -0,0 +1,6 @@
{
"guilds":{
}
}

91
handlers.py Normal file
View File

@@ -0,0 +1,91 @@
import os, datetime, disnake, sys, json
from disnake.ext import commands
from asyncio import sleep
from log import rootLogger
from pathlib import Path
from os import environ
import psycopg2
def takeSettings(guild_id, data):
path = Path("guilds/guilds.json")
readedData = json.loads(path.read_text(encoding="utf-8"))
pon = readedData["guilds"][f"{guild_id}"][f"{data}"]
return pon
def execute(command:str, isNeedToGiveData: bool = False):
with psycopg2.connect(
environ.get("PSQL_HOST"),
dbname=environ.get("PSQL_DBNAME"),
port=environ.get("PSQL_PORT", "5432"),
user=environ.get("PSQL_USER"),
password=environ.get("PSQL_PASSWORD")
) as conn:
cur = conn.cursor()
cur.execute(command)
conn.commit()
conn.close()
if isNeedToGiveData: return cur.fetchone()
else: return
TOKEN = environ.get("TOKEN")
api_token = environ.get("API_TOKEN")
api_id = environ.get("API_ID")
main_path = __file__.replace(os.path.basename(__file__), "")
bot = commands.Bot(command_prefix="/", intents=disnake.Intents().all())
bot.remove_command("help")
now = datetime.datetime.now().strftime("%d/%m/%Y %H:%M")
@bot.listen()
async def on_ready():
status = [disnake.Status.online, disnake.Status.idle, disnake.Status.dnd]
rootLogger.warning(f"{bot.user} is online and connected to Discord.")
disnakeGameStatus = disnake.Game(name="Only slash commands! Author github: github.com/yawaflua", type=4)
for filename in os.listdir(f"{main_path}/cogs"):
if filename.endswith(".py"):
namefile = filename.replace(".py", '')
bot.load_extension(f"cogs.{namefile}")
i = 0
while True:
await bot.change_presence(status=status[i], activity=disnakeGameStatus)
if i >= 2: i = 0
i = i+1
await sleep(30)
@bot.command(is_owner=True, pass_context=True, alias="reload")
async def reload(ctx):
for filename in os.listdir(f"{main_path}/cogs"):
if filename.endswith(".py"):
namefile = filename.replace(".py", '')
bot.reload_extension(f"cogs.{namefile}")
await ctx.message.delete()
@bot.command( pass_context = True, alias="clear")
@commands.has_permissions(manage_messages=True)
async def clear( ctx, amount = 1 ):
await ctx.channel.purge( limit = 1 )
await ctx.channel.purge( limit = amount )
@bot.command(is_owner=True, alias='leave')
async def leave(ctx, arg):
print(arg)
await bot.get_guild(int(arg)).leave()
if __name__ == "__main__":
try:
bot.run(TOKEN)
except ConnectionError as e:
rootLogger.error(f"Time: {now}, Internet exception: {e}. Closing the process....")
sys.exit()
except Exception as e:
rootLogger.error(f"Time: {now} Exception: {e}. Writing in file...")
with open("logs/last_error.log", "a") as file:
file.write(e)
file.close()

48
localization/ru.json Normal file
View File

@@ -0,0 +1,48 @@
{
"CREATE_MODAL_NAME": "создание-заявок",
"CREATE_MODAL_DESC":"Создание собственных анкет(Модалов)",
"CLEAR_NAME": "очистить",
"CLEAR_DESC": "Очищает сообщения в чате",
"CREATE_EMBED_DESC": "Создание Embed сообщения",
"MUTE_NAME": "мут",
"APP_MUTE_NAME": "Замутить",
"MUTE_DESC":"Замутить пользователя",
"ENABLEWLOWMODE_NAME": "включить-медленный-режим",
"ENABLEWLOWMODE_DESC": "Включает слоумод в канале",
"UNMUTE_NAME": "размут",
"UNMUTE_DESC": "Размутить пользователя",
"CHANGENICK_NAME": "сменить-ник",
"CHANGENICK_DESC": "Смена ника выбранному пользователю(после 3 раз мут)",
"SETTINGS": "настройки",
"SETUP_NAME": "базовая-настройка",
"SETUP_DESC": "Базовая настройка бота для этого сервера.",
"GUESTROOM_NAME": "оповещение-о-входе",
"GUESTROOM_DESC": "Настройка оповещения о входе / выходе игрока на / с сервер(а)",
"AUTOBRENCH_NAME": "автоматическое-создание-веток",
"AUTOBRENCH_DESC": "Настройка автоматического создания веток в определенном канале",
"AUTOREACTION_NAME": "автореакции",
"AUTOREACTION_DESC": "Настройка автоматических реакций в канале",
"AUTH_DESC": "Аутентификация пользователя, если тот есть в базе данных сервера",
"AUTOVOICE_NAME": "приватки",
"AUTOVOICE_DESC": "Автоматическое создание голосовых каналов(Если пользователь подключается к [+] СОЗДАТЬ)",
"AUTOVOICE_ON": "Включить приватки",
"AUTOVOICE_OFF": "Выключить приватки",
"SAVECHANNEL_NAME": "сохранить-канал",
"SAVECHANNEL_DESC": "Сохраняет канал и отправляет его как файл",
"TICKET_NAME": "создание-тикетов",
"TICKET_DESC": "Создает сообщение для открытия тикетов(До 3 кнопок)",
"GET_AVATAR": "Получить аватарку",
"REPORT": "Кинуть репорт",
"CHANGEFIELD": "Сменить Field",
"ISSUE_ROLE_NAME": "выдача-ролей",
"ISSUE_ROLE_DESC": "Выдача ролей по нажатию на кнопку"
}

31
log.py Normal file
View File

@@ -0,0 +1,31 @@
import logging
import os
import random
main_path = __file__.replace(os.path.basename(__file__), '')
formatter = "[%(asctime)s] %(message)s"
logFormatter = logging.Formatter(formatter)
logging.basicConfig(format=formatter)
logging.basicConfig(level=logging.INFO)
global rootLogger
fileHandler = logging.FileHandler("{0}/{1}.txt".format(f'{main_path}/logs', 'DISCORD_LOG'))
fileHandler.setFormatter(logFormatter)
if os.path.getsize(f'{main_path}/logs/DISCORD_LOG.txt') >= 52428800:
fileHandler.close()
a = random.random()
os.rename(f'{main_path}/logs/DISCORD_LOG.txt', f'DISCORD_LOG_{a}.txt')
with open(f'{main_path}/logs/DISCORD_LOG.txt', 'w+') as file:
file.write('Cleaning up logs!')
file.close()
logging.basicConfig(level=logging.WARNING)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger = logging.getLogger()
rootLogger.addHandler(fileHandler)
# rootLogger.addHandler(consoleHandler)

5
mute.json Normal file
View File

@@ -0,0 +1,5 @@
{
"mutes":[{
}]
}

17
requirements.txt Normal file
View File

@@ -0,0 +1,17 @@
aiogram==2.25.1
aiohttp==3.8.4
chat_exporter==2.6.1
config==0.5.1
dislash.py==1.4.9
disnake==2.9.0
Django==4.2.3
mojang==0.2.0
Pillow==9.5.0
Pillow==10.0.0
psycopg2_binary==2.9.6
Py_SPW==1.4.4
Requests==2.31.0
validators==0.20.0
yandex_music==2.1.1
yt_dlp==2023.3.4
ytmusicapi==1.1.0

4
start.py Normal file
View File

@@ -0,0 +1,4 @@
from handlers import *
from config import TOKEN

1
tempFiles/__init__.py Normal file
View File

@@ -0,0 +1 @@
# just ignore this

5
tempFiles/ticket.json Normal file
View File

@@ -0,0 +1,5 @@
{
"ticket": {
}
}

3
tempFiles/voiceName.json Normal file
View File

@@ -0,0 +1,3 @@
{
}

View File

@@ -0,0 +1,3 @@
{
}

6
tickets/tickets.json Normal file
View File

@@ -0,0 +1,6 @@
{
"tickets":{
}
}

2
users/users.json Normal file
View File

@@ -0,0 +1,2 @@
{}