Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ DISCORD_BOT_TOKEN=your_discord_bot_token_here

# CTF Tracking Configuration
CHECK_INTERVAL_MINUTES=30
ANNOUNCEMENT_CHANNEL_NAME=your_channel_name_here
ANNOUNCEMENT_CHANNEL_ID=your_channel_id_here
CTF_CHANNEL_CATETORY_ID=your_category_id_here

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
CTF_CHANNEL_CATETORY_ID=your_category_id_here
CTF_CHANNEL_CATEGORY_ID=your_category_id_here

Copilot uses AI. Check for mistakes.

# Misc
TIMEZONE="Asia/Taipei"
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ Then edit the `.env` file with your specific settings. Focus on these key variab
|----------|-------------|---------|
| `DISCORD_BOT_TOKEN` | Your Discord bot token | `MTIzNDU2Nzg5...` |
| `CHECK_INTERVAL_MINUTES` | How often to check for new CTFs | `30` (default) |
| `ANNOUNCEMENT_CHANNEL_ID` | Channel name for announcements | `ctf-announcements` |
| `ANNOUNCEMENT_CHANNEL_ID` | Channel id for announcements | `911612541829009418` |
| `CTF_CHANNEL_CATETORY_ID` | Category id for CTF event channel creations | `1454642939559940329` |

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
| `CTF_CHANNEL_CATETORY_ID` | Category id for CTF event channel creations | `1454642939559940329` |
| `CTF_CHANNEL_CATEGORY_ID` | Category id for CTF event channel creations | `1454642939559940329` |

Copilot uses AI. Check for mistakes.
| `TIMEZONE` | time zone for displaying | `Asia/Taipei` (default) |

*Other configuration options can remain at their default values.*

Expand Down Expand Up @@ -119,4 +121,4 @@ Once running, the bot will:

1. Automatically check CTFtime.org for new CTF events
2. Post announcements in your designated Discord channel
3. Use `data/known_events.json` to track announced events and avoid duplicates
3. Use `data/database.db` to track announced events, avoid duplicates, record CTF event channel, and more.
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ dependencies = [
"sqlalchemy>=2.0.45",
"aiosqlite>=0.22.1",
"pydantic-settings>=2.12.0",
"fastapi>=0.128.0",
"uvicorn>=0.40.0",
]

[dependency-groups]
Expand Down
25 changes: 20 additions & 5 deletions setup_env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,23 @@ fi
echo ""
echo "Announcement Channel ID:"
echo " The Discord channel where CTF announcements will be posted"
echo " The channel name that on your server"
echo " The channel id that on your server"
while true; do
read -p " Paste your Discord Channel Name: " ANNOUNCEMENT_CHANNEL_NAME
if [ -n "$ANNOUNCEMENT_CHANNEL_NAME" ]; then
read -p " Paste your Discord Channel ID: " ANNOUNCEMENT_CHANNEL_ID
if [ -n "$ANNOUNCEMENT_CHANNEL_ID" ]; then
break
else
echo " Error: Discord Channel Name cannot be empty. Please try again."

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message still refers to "Discord Channel Name" but the prompt has been changed to request "Discord Channel ID". The error message should be updated to match the new prompt context.

Copilot uses AI. Check for mistakes.
fi
done

echo ""
echo "CTF Channel Category ID:"
echo " The Discord category where CTF channels will be created"
echo " The category id that on your server"
while true; do
read -p " Paste your Discord Category ID: " CTF_CHANNEL_CATETORY_ID
if [ -n "$CTF_CHANNEL_CATETORY_ID" ]; then
Comment on lines +130 to +131

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
read -p " Paste your Discord Category ID: " CTF_CHANNEL_CATETORY_ID
if [ -n "$CTF_CHANNEL_CATETORY_ID" ]; then
read -p " Paste your Discord Category ID: " CTF_CHANNEL_CATEGORY_ID
if [ -n "$CTF_CHANNEL_CATEGORY_ID" ]; then

Copilot uses AI. Check for mistakes.
Comment on lines +130 to +131

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
read -p " Paste your Discord Category ID: " CTF_CHANNEL_CATETORY_ID
if [ -n "$CTF_CHANNEL_CATETORY_ID" ]; then
read -p " Paste your Discord Category ID: " CTF_CHANNEL_CATEGORY_ID
if [ -n "$CTF_CHANNEL_CATEGORY_ID" ]; then
# Backward compatibility: keep old misspelled variable name in sync
CTF_CHANNEL_CATETORY_ID="$CTF_CHANNEL_CATEGORY_ID"

Copilot uses AI. Check for mistakes.
break
else
echo " Error: Discord Channel Name cannot be empty. Please try again."

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message still refers to "Discord Channel Name" but the prompt has been changed to request "Discord Category ID". The error message should be updated to match the new prompt context.

Suggested change
echo " Error: Discord Channel Name cannot be empty. Please try again."
echo " Error: Discord Category ID cannot be empty. Please try again."

Copilot uses AI. Check for mistakes.
Expand All @@ -135,7 +148,8 @@ echo ""
echo "Please review your configuration:"
echo " Discord Bot Token: ${DISCORD_BOT_TOKEN:0:30}********** (hidden)"
echo " Check Interval: $CHECK_INTERVAL_MINUTES minutes"
echo " Announcement Channel Name: $ANNOUNCEMENT_CHANNEL_NAME"
echo " Announcement Channel ID: $ANNOUNCEMENT_CHANNEL_ID"
echo " CTF Channel Category ID: $CTF_CHANNEL_CATETORY_ID"

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Copilot uses AI. Check for mistakes.
echo " Time Zone: $TIMEZONE"
echo ""

Expand Down Expand Up @@ -166,7 +180,8 @@ DISCORD_BOT_TOKEN=$DISCORD_BOT_TOKEN

# CTF Tracking Configuration
CHECK_INTERVAL_MINUTES=$CHECK_INTERVAL_MINUTES
ANNOUNCEMENT_CHANNEL_NAME=$ANNOUNCEMENT_CHANNEL_NAME
ANNOUNCEMENT_CHANNEL_ID=$ANNOUNCEMENT_CHANNEL_ID
CTF_CHANNEL_CATETORY_ID=$CTF_CHANNEL_CATETORY_ID

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
CTF_CHANNEL_CATETORY_ID=$CTF_CHANNEL_CATETORY_ID
CTF_CHANNEL_CATEGORY_ID=$CTF_CHANNEL_CATEGORY_ID

Copilot uses AI. Check for mistakes.

# Misc
TIMEZONE="$TIMEZONE"
Expand Down
17 changes: 5 additions & 12 deletions src/cogs/bgtask_interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,13 @@

# utils
async def get_announcement_channel(bot:commands.Bot) -> discord.TextChannel:
channel_name = settings.ANNOUNCEMENT_CHANNEL_NAME

channel = None
for guild in bot.guilds:
for text_channel in guild.text_channels:
if text_channel.name.lower() == channel_name.lower():
channel = text_channel
break
if channel:
break
channel_id = settings.ANNOUNCEMENT_CHANNEL_ID
channel = bot.get_channel(channel_id)

if not channel:
logger.error(f"Can't find channel named '{channel_name}'")
logger.error(f"Can't find channel id={channel_id}")
logger.error(f"Please check:")
logger.error(f"1. Channel name is correct: {channel_name}")
logger.error(f"1. Channel ID is correct: {channel_id}")
logger.error(f"2. Bot has permission to view the channel")
logger.error(f"3. The channel exists in the server where the Bot is located")
await bot.close()
Expand Down Expand Up @@ -85,6 +77,7 @@ async def task_checks(self):
await crud.create_event(session, new_events_db)

for event in new_events_ctftime:
event_id = event["id"]
embed = await create_event_embed(event, "有新的 CTF 競賽!")

view = discord.ui.View(timeout=None)
Expand Down
17 changes: 13 additions & 4 deletions src/cogs/ctf.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,11 @@ async def callback(self, interaction: discord.Interaction):
channel_name = self.children[0].value

# find category
category_name = "Incoming/Running CTF"
category_id = settings.CTF_CHANNEL_CATETORY_ID

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
category_id = settings.CTF_CHANNEL_CATETORY_ID
category_id = settings.CTF_CHANNEL_CATEGORY_ID

Copilot uses AI. Check for mistakes.
guild = interaction.guild
category = discord.utils.get(interaction.guild.categories, name=category_name)
category = discord.utils.get(interaction.guild.categories, id=category_id)
if category is None:
await interaction.followup.send(content=f"Category '{category_name}' not found.", ephemeral=True)
await interaction.followup.send(content=f"Category id={category_id} not found", ephemeral=True)

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message incorrectly states the category should have "name=category_name" when the code is now using ID-based lookup with "id=category_id". The error message should be updated to reflect that category lookup is now based on ID, not name.

Copilot uses AI. Check for mistakes.
return

# create channel
Expand Down Expand Up @@ -205,17 +205,26 @@ async def ctf_menu(self, ctx:discord.ApplicationContext):
known_events:List[Event] = await crud.read_event(session)

# embed
time_now = datetime.now().timestamp()

embed = discord.Embed(
title=f"{settings.EMOJI} CTF events tracked",
color=discord.Color.green()
)
for event in known_events:
mark = ""
if not(event.channel_id is None):
mark += "[⭐️]"
if event.start <= time_now and event.finish >= time_now:
mark += "[🏃]"

embed.add_field(
name=f"[id={event.event_id}] {event.title}",
name=f"{mark}[id={event.event_id}] {event.title}",
value=f"start at {datetime.fromtimestamp(event.start).astimezone(ZoneInfo(settings.TIMEZONE))}\n\
finish at {datetime.fromtimestamp(event.finish).astimezone(ZoneInfo(settings.TIMEZONE))}",
inline=False
)
embed.set_footer(text="[🏃] running ctf\n[⭐️] channel created")

await ctx.response.send_message(embed=embed, view=CTFMenuView(self.bot), ephemeral=True)

Expand Down
7 changes: 2 additions & 5 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,14 @@ class Settings(BaseSettings):
# CTFTime tracking configuration
CTFTIME_API_URL:str="https://ctftime.org/api/v1/events/"
TEAM_API_URL:str="https://ctftime.org/api/v1/teams/"
CTFTIME_SEARCH_DAYS:int=+90
DATABASE_SEARCH_DAYS:int=-90 # known events: finish > now_day+(-90)
ANNOUNCEMENT_CHANNEL_NAME:str
ANNOUNCEMENT_CHANNEL_ID:int
CTF_CHANNEL_CATETORY_ID:int

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This typo appears in the configuration variable name and should be corrected to maintain consistency with standard English spelling.

Suggested change
CTF_CHANNEL_CATETORY_ID:int
CTF_CHANNEL_CATEGORY_ID:int

Copilot uses AI. Check for mistakes.
CHECK_INTERVAL_MINUTES:int

# Database configuration
DATABASE_URL:str="sqlite+aiosqlite:///data/database.db"

# Notification (todo)
#NOTIFY_BEFORE_EVENT:int = 1 * 24 * 60 * 60

# Misc
TIMEZONE:str
EMOJI:str="🚩"
Expand Down
2 changes: 1 addition & 1 deletion src/utils/ctf_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ async def fetch_ctf_events(event_id:Optional[int]=None) -> List[Dict[str, Any]]:
params = {
"limit": 20,
"start": int(datetime.now().timestamp()),
"finish": int((datetime.now() + timedelta(days=settings.CTFTIME_SEARCH_DAYS)).timestamp()),
#"finish": int((datetime.now() + timedelta(days=settings.CTFTIME_SEARCH_DAYS)).timestamp()),

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should be removed rather than left in the codebase. The "finish" parameter is commented out which removes the time range filter for CTF event searches. If this is intentional to fetch all future events, the parameter should be removed entirely. If the parameter is still needed, it should be properly implemented. Leaving commented code creates confusion about the intended behavior.

Suggested change
#"finish": int((datetime.now() + timedelta(days=settings.CTFTIME_SEARCH_DAYS)).timestamp()),

Copilot uses AI. Check for mistakes.
}

url = settings.CTFTIME_API_URL
Expand Down
7 changes: 4 additions & 3 deletions src/utils/join_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from src import crud
from src.utils.ctf_api import fetch_ctf_events
from src.utils.embed_creator import create_event_embed
from src.config import settings

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -59,11 +60,11 @@ async def join_channel(
event_api:Event = events_api[0]

# create channel
category_name = "Incoming/Running CTF"
category_id = settings.CTF_CHANNEL_CATETORY_ID

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error in variable name: "CATETORY" should be "CATEGORY". This should match the corrected spelling in the configuration.

Suggested change
category_id = settings.CTF_CHANNEL_CATETORY_ID
category_id = settings.CTF_CHANNEL_CATEGORY_ID

Copilot uses AI. Check for mistakes.
guild = interaction.guild
category = discord.utils.get(interaction.guild.categories, name=category_name)
category = discord.utils.get(interaction.guild.categories, id=category_id)
if category is None:
await interaction.followup.send(content=f"Category '{category_name}' not found.", ephemeral=True)
await interaction.followup.send(content=f"Category id={category_id} not found", ephemeral=True)

Copilot AI Jan 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message incorrectly states the category should have "name=category_name" when the code is now using ID-based lookup with "id=category_id". The error message should be updated to reflect that category lookup is now based on ID, not name.

Copilot uses AI. Check for mistakes.
return

overwrites = {
Expand Down
86 changes: 86 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading