Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 47 additions & 23 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Any, Dict, List, Optional, Union

import discord
from discord import app_commands
from discord.ext import commands, tasks
from dotenv import load_dotenv

Expand All @@ -25,6 +26,9 @@ def _parse_id_list(env_val: str) -> List[int]:
return [int(x.strip()) for x in env_val.split(",") if x.strip().isdigit()]


GUILD_IDS = _parse_id_list(os.getenv("GUILD_ID", "1447887618317619261"))


def _parse_channel_role_map(env_val: str) -> Dict[int, int]:
""" "채널ID:역할ID,채널ID:역할ID" 형식 문자열을 파싱해 {채널ID: 역할ID} 매핑을 만든다."""
mapping: Dict[int, int] = {}
Expand Down Expand Up @@ -173,7 +177,6 @@ def make_confirmed_embed(lecture: Dict[str, Any], enrolled_count: int) -> discor


def _get_channel_mention(channel_id: int) -> str:
"""채널이 속한 길드 안에서 해당 채널에 매핑된 역할만 멘션 문자열로 반환한다."""
role_id = NOTIFY_CHANNEL_ROLE_MAP.get(channel_id)
if not role_id:
return ""
Expand Down Expand Up @@ -271,13 +274,13 @@ async def before_poll() -> None:
print(f"[초기화 오류] {type(exc).__name__}: {exc}")


@bot.command(name="릴스")
async def cmd_rels(ctx: commands.Context) -> None:
@bot.tree.command(name="릴스", description="현재 신청 가능한 강연 목록 보기")
async def cmd_rels(interaction: discord.Interaction) -> None:
try:
lectures = fetch_active_lectures()

if not lectures:
await ctx.send("현재 신청 가능한 강연이 없어요.")
await interaction.response.send_message("현재 신청 가능한 강연이 없어요.")
return

display_lectures = lectures[:25]
Expand Down Expand Up @@ -312,20 +315,20 @@ async def cmd_rels(ctx: commands.Context) -> None:
" • 25개 이상의 강연 중 상위 25개만 표시됨" if len(lectures) > 25 else ""
)
embed.set_footer(text=f"{FOOTER_TEXT}{footer_note}")
await ctx.send(embed=embed)
await interaction.response.send_message(embed=embed)

except Exception as exc:
await ctx.send(f"오류가 발생했어요: {exc}")
await interaction.response.send_message(f"오류가 발생했어요: {exc}")


@bot.command(name="인원")
async def cmd_headcount(ctx: commands.Context) -> None:
@bot.tree.command(name="인원", description="강연별 신청 인원 현황 보기")
async def cmd_headcount(interaction: discord.Interaction) -> None:
try:
lectures = fetch_all_lectures_basic()
enroll_map = fetch_enrollment_counts(lectures)

if not lectures:
await ctx.send("현재 진행 중인 강연이 없어요.")
await interaction.response.send_message("현재 진행 중인 강연이 없어요.")
return

embed = discord.Embed(
Expand All @@ -352,20 +355,20 @@ async def cmd_headcount(ctx: commands.Context) -> None:
embed.add_field(name=lecture["title"], value=value, inline=False)

embed.set_footer(text=FOOTER_TEXT)
await ctx.send(embed=embed)
await interaction.response.send_message(embed=embed)

except Exception as exc:
await ctx.send(f"오류가 발생했어요: {exc}")
await interaction.response.send_message(f"오류가 발생했어요: {exc}")


@bot.command(name="도움말")
async def cmd_help(ctx: commands.Context) -> None:
@bot.tree.command(name="도움말", description="명령어 안내")
async def cmd_help(interaction: discord.Interaction) -> None:
embed = discord.Embed(title="릴스 봇 명령어 목록", color=EMBED_COLOR)
embed.add_field(name="!릴스", value="현재 신청 가능한 강연 목록 보기", inline=False)
embed.add_field(name="!인원", value="강연별 신청 인원 현황 보기", inline=False)
embed.add_field(name="!도움말", value="명령어 안내", inline=False)
embed.add_field(name="/릴스", value="현재 신청 가능한 강연 목록 보기", inline=False)
embed.add_field(name="/인원", value="강연별 신청 인원 현황 보기", inline=False)
embed.add_field(name="/도움말", value="명령어 안내", inline=False)
embed.set_footer(text=FOOTER_TEXT)
await ctx.send(embed=embed)
await interaction.response.send_message(embed=embed)


@bot.event
Expand All @@ -374,13 +377,34 @@ async def on_ready() -> None:
if not poll_api.is_running():
poll_api.start()


@bot.event
async def on_command_error(ctx: commands.Context, error: Exception) -> None:
if isinstance(error, commands.CommandNotFound):
await ctx.send("없는 명령어예요. `!도움말`로 명령어 목록을 확인해보세요!")
try:
if GUILD_IDS:
for guild_id in GUILD_IDS:
guild_obj = discord.Object(id=guild_id)
bot.tree.copy_global_to(guild=guild_obj)
synced = await bot.tree.sync(guild=guild_obj)
print(
f"[슬래시 동기화] 길드 {guild_id}: {len(synced)}개 명령어 동기화 완료"
)
else:
synced = await bot.tree.sync()
print(
f"[슬래시 동기화] 전역: {len(synced)}개 명령어 동기화 완료 (반영까지 최대 1시간 소요될 수 있음)"
)
except Exception as e:
print(f"[슬래시 동기화 오류] {e}")


@bot.tree.error
async def on_app_command_error(
interaction: discord.Interaction, error: app_commands.AppCommandError
) -> None:
print(f"[명령어 오류] {error}")
message = "명령어 실행 중 오류가 발생했어요."
if interaction.response.is_done():
await interaction.followup.send(message, ephemeral=True)
else:
raise error
await interaction.response.send_message(message, ephemeral=True)


if __name__ == "__main__":
Expand Down
Loading