Skip to content

Commit

Permalink
Release version v3.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
regunakyle committed Apr 18, 2024
2 parents e9c80e5 + d1c73d2 commit b6e764d
Show file tree
Hide file tree
Showing 25 changed files with 565 additions and 650 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1

FROM python:3.12 AS compile-image
FROM python:3.11 AS compile-image

WORKDIR /app

Expand All @@ -9,7 +9,7 @@ COPY init.sh requirements.txt ./
RUN chmod u+x ./init.sh && \
./init.sh

FROM python:3.12-slim AS build-image
FROM python:3.11-slim AS build-image
COPY --from=compile-image /opt/venv /opt/venv
COPY --from=compile-image /bin/ffmpeg /bin/ffmpeg

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Data are stored in an embedded SQLite3 database file.

## Deployment guide

This Discord bot is developed with Python 3.11. Use the same Python version to ensure maximum compatibility.

1. Download the whole source code using `git clone`.

2. Rename `.env.example` to `.env` and put your Discord token inside.
Expand Down Expand Up @@ -36,7 +38,7 @@ Note: The `latest` tag refers to the latest stable version.
- [ ] General.chat
- [ ] Music.play: Add Spotify support
- [ ] Docker support iGPU for FFMPEG
- [ ] Change primary key of models to BigInteger
- [ ] Allow bot owner to run every command

## Notable commands

Expand Down
4 changes: 1 addition & 3 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ services:

lavalink:
container_name: lavalink
# Using fix-yt-400 until Lavalink fix the 400 issue
# https://github.com/lavalink-devs/lavaplayer/issues/69
image: ghcr.io/lavalink-devs/lavalink:fix-yt-400
image: ghcr.io/lavalink-devs/lavalink:4
environment:
server.port: 2333
lavalink.server.password: youshallnotpass
Expand Down
6 changes: 4 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,12 @@ def set_sqlite_pragma(

description = "Discord bot for self use. \nWritten in Python using discord.py."

bot = discordBot(os.getenv("PREFIX"), intents, activity, description, async_session)
bot = discordBot(
os.getenv("PREFIX", ">>"), intents, activity, description, async_session
)

logger.info("STARTING DISCORD BOT PROCESS...\n")
await bot.start(os.getenv("DISCORD_TOKEN"))
await bot.start(os.getenv("DISCORD_TOKEN", ""))


if __name__ == "__main__":
Expand Down
573 changes: 285 additions & 288 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[tool.poetry]
name = "my-discord-bot"
version = "2.3.1"
version = "2.5.1"
description = "Discord Bot by Reguna"
authors = ["Reguna <60984878+regunakyle@users.noreply.github.com>"]
package-mode = false

[tool.poetry.dependencies]
python = "^3.12"
python = "^3.11"
feedparser = "^6"
gallery-dl = "^1"
python-dotenv = "^1"
Expand Down
318 changes: 159 additions & 159 deletions requirements.txt

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .bot import discordBot
from src.bot import discordBot

__all__ = ("discordBot",)
14 changes: 6 additions & 8 deletions src/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from sqlalchemy import delete, select
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from . import cogs, models
from src import cogs, models

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,7 +48,7 @@ async def on_guild_join(self, guild: discord.Guild) -> None:
async with self.sessionmaker() as session:
try:
session.add(
models.GuildInfo(
models.Guild(
guild_id=guild.id,
guild_name=guild.name,
bot_channel=guild.system_channel.id
Expand All @@ -71,20 +71,18 @@ async def on_guild_remove(self, guild: discord.Guild) -> None:
async with self.sessionmaker() as session:
# Delete removed guild from database
await session.execute(
delete(models.GuildInfo).where(models.GuildInfo.guild_id == guild.id)
delete(models.Guild).where(models.Guild.guild_id == guild.id)
)
await session.commit()

async def on_member_join(self, member: discord.member) -> None:
async def on_member_join(self, member: discord.Member) -> None:
"""Called when a Member joins a Guild."""

channel = member.guild.system_channel
async with self.sessionmaker() as session:
guild: models.GuildInfo | None = (
guild: models.Guild | None = (
await session.execute(
select(models.GuildInfo).where(
models.GuildInfo.guild_id == member.guild.id
)
select(models.Guild).where(models.Guild.guild_id == member.guild.id)
)
).scalar()
if not guild:
Expand Down
12 changes: 7 additions & 5 deletions src/cogs/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from .error_handler import ErrorHandler
from .general import General
from .meta import Meta
from .music import Music
from .steam import Steam
from src.cogs.error_handler import ErrorHandler
from src.cogs.general import General
from src.cogs.meta import Meta
from src.cogs.music import Music
from src.cogs.steam import Steam

__all__ = ("ErrorHandler", "General", "Meta", "Music", "Steam")
11 changes: 9 additions & 2 deletions src/cogs/_cog_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,28 @@ def __init__(
self.bot = bot
self.sessionmaker = sessionmaker

def get_max_file_size(self, nitroCount: int = 0) -> int:
def get_max_file_size(
self,
guild: None | discord.Guild,
) -> int:
"""Return the maximum file size (in MiB) supported by the current guild.
If MAX_FILE_SIZE in .env is smaller than this size, return MAX_FILE_SIZE instead.
"""

if guild is None:
return 25

# Nitro level and their maximum upload size
nitroCount = guild.premium_subscription_count
maxSize = 100 # Level 3
if nitroCount < 7: # Level 1 or lower
maxSize = 25
elif nitroCount < 14: # Level 2
maxSize = 50

try:
return min(maxSize, abs(int(os.getenv("MAX_FILE_SIZE"))))
return min(maxSize, abs(int(os.getenv("MAX_FILE_SIZE", "25"))))
except Exception:
return maxSize

Expand Down
4 changes: 2 additions & 2 deletions src/cogs/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from discord.ext import commands
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from ._cog_base import CogBase
from src.cogs._cog_base import CogBase

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -39,7 +39,7 @@ async def on_app_command_error(
) and "error code: 40005" in str(e):
error["content"] = (
"I tried to upload a huge file and was rejected by Discord! (Maximum size: {size}MiB)".format(
size=self.get_max_file_size(ia.guild.premium_subscription_count)
size=self.get_max_file_size(ia.guild)
)
)
else:
Expand Down
8 changes: 3 additions & 5 deletions src/cogs/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from gallery_dl import config, job
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from ._cog_base import CogBase, check_cooldown
from src.cogs._cog_base import CogBase, check_cooldown

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -67,7 +67,7 @@ async def pixiv(
config.set(
("downloader",),
"filesize-max",
f"{self.get_max_file_size(ia.guild.premium_subscription_count)}M",
f"{self.get_max_file_size(ia.guild)}M",
)
config.set(
("extractor",),
Expand Down Expand Up @@ -119,9 +119,7 @@ async def pixiv(
# HttpError: Most probably because the image is too big
await ia.followup.send(
"Download failed. Most probably because your image is too big. (Maximum size: {size}MiB)".format(
size=self.get_max_file_size(
ia.guild.premium_subscription_count
)
size=self.get_max_file_size(ia.guild)
)
)
return
Expand Down
32 changes: 15 additions & 17 deletions src/cogs/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
from sqlalchemy import delete, insert, select, update
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from .. import models
from ._cog_base import CogBase
from src import models
from src.cogs._cog_base import CogBase

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -42,18 +42,16 @@ async def sync(
# Sync database with joined guilds
async with self.sessionmaker() as session:
await session.execute(
delete(models.GuildInfo).where(
~models.GuildInfo.guild_id.in_(
[guild.id for guild in self.bot.guilds]
)
delete(models.Guild).where(
~models.Guild.guild_id.in_([guild.id for guild in self.bot.guilds])
)
)

# TODO: Optimize
for guild in self.bot.guilds:
try:
await session.execute(
insert(models.GuildInfo).values(
insert(models.Guild).values(
guild_id=guild.id, guild_name=guild.name
)
)
Expand Down Expand Up @@ -128,15 +126,15 @@ async def set_bot_channel(self, ia: discord.Interaction) -> None:
async with self.sessionmaker() as session:
if (
await session.execute(
update(models.GuildInfo)
.where(models.GuildInfo.guild_id == ia.guild.id)
.where(models.GuildInfo.bot_channel == ia.channel.id)
update(models.Guild)
.where(models.Guild.guild_id == ia.guild.id)
.where(models.Guild.bot_channel == ia.channel.id)
.values(bot_channel=None)
)
).rowcount == 0:
await session.execute(
update(models.GuildInfo)
.where(models.GuildInfo.guild_id == ia.guild.id)
update(models.Guild)
.where(models.Guild.guild_id == ia.guild.id)
.values(bot_channel=ia.channel.id)
)

Expand Down Expand Up @@ -194,8 +192,8 @@ async def set_welcome_message(
async with self.sessionmaker() as session:
if not message:
await session.execute(
update(models.GuildInfo)
.where(models.GuildInfo.guild_id == ia.guild.id)
update(models.Guild)
.where(models.Guild.guild_id == ia.guild.id)
.values(welcome_message=None)
)
resp = "Welcome message cleared."
Expand All @@ -205,8 +203,8 @@ async def set_welcome_message(
"unicode-escape"
)
await session.execute(
update(models.GuildInfo)
.where(models.GuildInfo.guild_id == ia.guild.id)
update(models.Guild)
.where(models.Guild.guild_id == ia.guild.id)
.values(welcome_message=unescaped_msg)
)
resp = (
Expand Down Expand Up @@ -262,7 +260,7 @@ async def broadcast(self, ia: discord.Interaction, message: str = "") -> None:

async with self.sessionmaker() as session:
channels: ty.List[int] = (
await session.execute(select(models.GuildInfo.bot_channel))
await session.execute(select(models.Guild.bot_channel))
).scalars()
await ia.response.send_message("Broadcasting...")
for channel in channels:
Expand Down
36 changes: 17 additions & 19 deletions src/cogs/music.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import aiohttp
import discord
import wavelink
from discord.client import Client
from discord.ext import commands, tasks
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker

from ._cog_base import CogBase
from src.cogs._cog_base import CogBase

logger = logging.getLogger(__name__)

Expand All @@ -22,10 +23,11 @@ def check_node_exist(func: ty.Callable) -> ty.Callable:

@wraps(func)
async def _wrapper(
*args: ty.List["Music | discord.Interaction"], **kwargs: ty.Dict[str, ty.Any]
*args: ty.List["Music | discord.Interaction[Client]"],
**kwargs: ty.Dict[str, ty.Any],
) -> None:
"""args[0] is self, args[1] is an discord.Interaction object"""
interaction: discord.Interaction = args[1]
interaction: discord.Interaction[Client] = args[1]

try:
wavelink.Pool.get_node()
Expand All @@ -52,26 +54,22 @@ def __init__(
######################################
# UTILITIES

async def connect_node(self) -> ty.Dict[str, wavelink.Node]:
async def connect_node(self) -> None:
"""Connect to a Lavalink node."""
await self.bot.wait_until_ready()
logger.info("Attempting to connect to a node...")
try:
node = await wavelink.Pool.connect(
client=self.bot,
nodes=[
wavelink.Node(
uri=f'http://{os.getenv("LAVALINK_IP")}:{os.getenv("LAVALINK_PORT")}',
password=os.getenv("LAVALINK_PASSWORD", ""),
retries=3,
)
],
)
self.reconnect_count = 0
return node

except aiohttp.ClientConnectionError:
return {}
node = wavelink.Node(
uri=f'http://{os.getenv("LAVALINK_IP")}:{os.getenv("LAVALINK_PORT")}',
password=os.getenv("LAVALINK_PASSWORD", ""),
retries=3,
)
await wavelink.Pool.connect(
client=self.bot,
nodes=[node],
)
if node.status == wavelink.NodeStatus.CONNECTED:
self.reconnect_count = 0

@tasks.loop(minutes=1)
async def check_node_connection_task(self) -> None:
Expand Down
8 changes: 4 additions & 4 deletions src/cogs/steam.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from sqlalchemy.orm import selectinload

from .. import models
from ._cog_base import CogBase
from src import models
from src.cogs._cog_base import CogBase

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -202,7 +202,7 @@ async def giveawayTask(self) -> None:
await session.execute(
select(models.GuildTask)
.options(
selectinload(models.GuildTask.guild_info),
selectinload(models.GuildTask.guild),
)
.where(models.GuildTask.task_name == self.taskName)
)
Expand All @@ -214,7 +214,7 @@ async def giveawayTask(self) -> None:
logger.warning(
"This guild (id: {task_id}, name: {guild_name}) has not yet set a bot channel!".format(
task_id=guild_task.id,
guild_name=guild_task.guild_info.guild_name,
guild_name=guild_task.guild.guild_name,
)
)
continue
Expand Down
Loading

0 comments on commit b6e764d

Please sign in to comment.