dcchbot 1.8__py3-none-any.whl → 1.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
dcchbot/__init__.py CHANGED
@@ -1,5 +1,5 @@
1
1
  #init
2
2
  from .main import run
3
- print("Discord chinese bot v1.8 ok")
3
+ print("Discord chinese bot v1.8.1 ok")
4
4
  print("by I_am_from_taiwan")
5
5
  run()
dcchbot/main.py CHANGED
@@ -1,12 +1,18 @@
1
- # v1.8 修正版 main.py
2
1
  import logging
3
2
  import os
4
3
  import discord
5
4
  from discord.ext import commands
6
5
  from discord import app_commands
7
- from datetime import timedelta,datetime
6
+ from datetime import timedelta, datetime
7
+ """ver1.8.1"""
8
+ # ─── 全域變數 ────────────────────────────────────────────────────────────────
9
+ OWNER_ID = None
10
+ LOG_CHANNEL_ID = None
11
+ token = None
12
+ bot = None
13
+ now = datetime.now()
8
14
 
9
- # 自訂 Discord Log Handler,將 log 訊息傳送到指定頻道
15
+ # ─── Discord Log Handler ────────────────────────────────────────────────────
10
16
  class DiscordLogHandler(logging.Handler):
11
17
  def __init__(self, bot: commands.Bot, channel_id: int, level=logging.INFO):
12
18
  super().__init__(level)
@@ -24,17 +30,15 @@ class DiscordLogHandler(logging.Handler):
24
30
 
25
31
  def emit(self, record):
26
32
  log_entry = self.format(record)
27
- # 機器人未啟動或已關閉時跳過
28
33
  if self.bot.is_closed() or not self.bot.is_ready():
29
34
  return
30
- coro = self.send_log(log_entry[:1900]) # Discord 字數限制
35
+ coro = self.send_log(log_entry[:1900])
31
36
  try:
32
37
  self.bot.loop.create_task(coro)
33
38
  except RuntimeError:
34
- pass # event loop 尚未啟動時跳過
35
- now = datetime.now()
39
+ pass
36
40
 
37
- # 建立 logs 資料夾並設定基本 logging
41
+ # ─── Logging 基本設定 ────────────────────────────────────────────────────────
38
42
  os.makedirs("logs", exist_ok=True)
39
43
  logging.basicConfig(
40
44
  level=logging.INFO,
@@ -46,25 +50,22 @@ logging.basicConfig(
46
50
  )
47
51
  logger = logging.getLogger(__name__)
48
52
 
49
-
53
+ # ─── 啟動主函式 ──────────────────────────────────────────────────────────────
50
54
  def run():
51
- # 先輸入設定,避免非同步使用時參數錯誤
55
+ global OWNER_ID, LOG_CHANNEL_ID, token, bot
56
+
52
57
  OWNER_ID = int(input("請輸入你的 Discord User ID:\n> ").strip())
53
58
  LOG_CHANNEL_ID = int(input("請輸入你的 Log 頻道 ID:\n> ").strip())
54
59
  token = input("請輸入你的 Discord Bot Token:\n> ").strip()
55
60
 
56
61
  intents = discord.Intents.all()
57
- # discord.Intents.all() 已包含所有必要權限,無需重覆設定
58
-
59
62
  bot = commands.Bot(command_prefix="!", intents=intents)
60
63
  CODER_ID = 1317800611441283139
61
64
 
62
- # 建立自訂 log handler 並加到 logger
63
65
  discord_handler = DiscordLogHandler(bot, LOG_CHANNEL_ID)
64
66
  discord_handler.setFormatter(logging.Formatter('%(asctime)s | %(levelname)s | %(message)s'))
65
67
  logger.addHandler(discord_handler)
66
68
 
67
- # 把 token 暫存到 bot,方便指令存取
68
69
  bot._token = token
69
70
 
70
71
  def is_admin(interaction: discord.Interaction) -> bool:
@@ -79,10 +80,8 @@ def run():
79
80
  except Exception:
80
81
  logger.exception("同步 Slash 指令失敗:")
81
82
  logger.info(f"機器人上線:{bot.user}")
82
- logger.info(f"token {token}")
83
- logger.info(f"OWNER_ID {OWNER_ID}")
84
- logger.info(f"log ID {LOG_CHANNEL_ID}")
85
83
  logger.info(f"powered by dcchbot")
84
+
86
85
  # ─── Slash Commands ────────────────────────────────────────────────────────
87
86
 
88
87
  @bot.tree.command(name="hello", description="跟你說哈囉")
@@ -105,56 +104,48 @@ def run():
105
104
  @bot.tree.command(name="ban", description="封鎖使用者(限管理員)")
106
105
  @app_commands.describe(member="要封鎖的使用者", reason="封鎖原因")
107
106
  async def ban(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
108
- logger.info(f"{interaction.user} 嘗試封鎖 {member},原因:{reason}")
109
107
  if not is_admin(interaction):
110
108
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
111
109
  try:
112
110
  await member.ban(reason=reason)
113
111
  await interaction.response.send_message(f"{member.mention} 已被封鎖。原因:{reason}")
114
112
  except discord.Forbidden:
115
- logger.warning(f"封鎖失敗:權限不足 ({member})")
116
- await interaction.response.send_message("無法封鎖對方,可能因為權限不足或目標層級過高。", ephemeral=True)
113
+ await interaction.response.send_message("權限不足,封鎖失敗。", ephemeral=True)
117
114
 
118
115
  @bot.tree.command(name="kick", description="踢出使用者(限管理員)")
119
116
  @app_commands.describe(member="要踢出的使用者", reason="踢出原因")
120
117
  async def kick(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
121
- logger.info(f"{interaction.user} 嘗試踢出 {member},原因:{reason}")
122
118
  if not is_admin(interaction):
123
119
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
124
120
  try:
125
121
  await member.kick(reason=reason)
126
122
  await interaction.response.send_message(f"{member.mention} 已被踢出。原因:{reason}")
127
123
  except discord.Forbidden:
128
- await interaction.response.send_message("無法踢出對方,可能因為權限不足或目標層級過高。", ephemeral=True)
129
- @bot.tree.command(name="shutthefuckup", description="暫時請使用者閉嘴(限管理員)")
130
- @app_commands.describe(member="要禁言的使用者", seconds="禁言秒數", reason="禁言原因")
131
- async def timeout(interaction: discord.Interaction, member: discord.Member, seconds: int, reason: str = "未提供原因"):
132
- if not is_admin(interaction):
133
- return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
134
- try:
135
- until = datetime.utcnow() + timedelta(seconds=seconds)
136
- await member.timeout(until, reason=reason)
137
- await interaction.response.send_message(f"{member.mention} 已被禁言 {seconds} 秒。原因:{reason}")
138
- except Exception as e:
139
- await interaction.response.send_message(f"無法禁言:{e}")
140
-
124
+ await interaction.response.send_message("權限不足,踢出失敗。", ephemeral=True)
141
125
 
142
126
  @bot.tree.command(name="warn", description="警告使用者(限管理員)")
143
127
  @app_commands.describe(member="要警告的使用者", reason="警告原因")
144
128
  async def warn(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
145
- logger.info(f"{interaction.user} 警告 {member},原因:{reason}")
146
129
  if not is_admin(interaction):
147
130
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
148
131
  await interaction.response.send_message(f"{member.mention} 已被警告。原因:{reason}")
149
132
  try:
150
133
  await member.send(f"你在伺服器 {interaction.guild.name} 被警告:{reason}")
151
134
  except:
152
- await interaction.followup.send("無法傳送私人訊息給該用戶。")
135
+ pass
136
+
137
+ @bot.tree.command(name="shutthefuckup", description="暫時禁言使用者(限管理員)")
138
+ @app_commands.describe(member="要禁言的使用者", seconds="禁言秒數", reason="禁言原因")
139
+ async def timeout(interaction: discord.Interaction, member: discord.Member, seconds: int, reason: str = "未提供原因"):
140
+ if not is_admin(interaction):
141
+ return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
142
+ until = datetime.utcnow() + timedelta(seconds=seconds)
143
+ await member.timeout(until, reason=reason)
144
+ await interaction.response.send_message(f"{member.mention} 已被禁言 {seconds} 秒。")
153
145
 
154
146
  @bot.tree.command(name="moderate", description="打開管理 GUI 面板")
155
147
  @app_commands.describe(member="要管理的對象")
156
148
  async def moderate(interaction: discord.Interaction, member: discord.Member):
157
- logger.info(f"{interaction.user} 打開 GUI 對 {member}")
158
149
  if not is_admin(interaction):
159
150
  return await interaction.response.send_message("你沒有權限使用此指令。", ephemeral=True)
160
151
  view = ModerationView(member, interaction.user)
@@ -164,7 +155,6 @@ def run():
164
155
 
165
156
  @bot.tree.command(name="stop", description="關閉機器人(限擁有者)")
166
157
  async def stop(interaction: discord.Interaction):
167
- logger.info(f"{interaction.user} 嘗試關閉機器人")
168
158
  if interaction.user.id != OWNER_ID and interaction.user.id != CODER_ID:
169
159
  return await interaction.response.send_message("只有擁有者可以使用此指令。", ephemeral=True)
170
160
  await interaction.response.send_message("機器人即將關閉。")
@@ -175,120 +165,102 @@ def run():
175
165
  if interaction.user.id != OWNER_ID and interaction.user.id != CODER_ID:
176
166
  return await interaction.response.send_message("只有擁有者可以使用此指令。", ephemeral=True)
177
167
  await interaction.response.send_message(bot._token)
178
- @bot.tree.command(name="log", description="紀錄log(管理員)")
168
+
169
+ @bot.tree.command(name="log", description="紀錄 log(限管理員)")
179
170
  @app_commands.describe(log="內容")
180
- async def log(interaction: discord.Interaction, log: str = "null"):
171
+ async def log_cmd(interaction: discord.Interaction, log: str = "null"):
181
172
  if not is_admin(interaction):
182
173
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
183
- try:
184
- logger.info(f"{log}")
185
- except Exception as e:
186
- interaction.response.send_message(f"無法紀錄:{e}")
174
+ try:
175
+ logger.info(f"{log}")
176
+ await interaction.response.send_message("Log 已紀錄。")
177
+ except Exception as e:
178
+ await interaction.response.send_message(f"無法紀錄:{e}")
179
+
187
180
  @bot.tree.command(name="time", description="顯示時間")
188
- async def say(interaction: discord.Interaction):
181
+ async def time(interaction: discord.Interaction):
189
182
  logger.info(f"{interaction.user} 使用 /time:{now}")
190
- await interaction.response.send_message(now)
191
- # ─── View 類 ────────────────────────────────────────────────────────────────
183
+ await interaction.response.send_message(str(now))
192
184
 
185
+ try:
186
+ logger.info("正在啟動機器人...")
187
+ bot.run(token)
188
+ except discord.LoginFailure:
189
+ logger.error("Token 無效,請重新確認。")
190
+ except Exception as e:
191
+ logger.exception(f"發生錯誤:{e}")
192
+
193
+ # ─── GUI 面板 ────────────────────────────────────────────────────────────────
193
194
  class ModerationView(discord.ui.View):
194
- def __init__(self, member: discord.Member, author: discord.Member):
195
- super().__init__(timeout=60)
196
- self.member = member
197
- self.author = author
195
+ def __init__(self, member: discord.Member, author: discord.Member):
196
+ super().__init__(timeout=60)
197
+ self.member = member
198
+ self.author = author
198
199
 
199
- async def interaction_check(self, interaction: discord.Interaction) -> bool:
200
- return interaction.user.id == self.author.id
200
+ async def interaction_check(self, interaction: discord.Interaction) -> bool:
201
+ return interaction.user.id == self.author.id
201
202
 
202
- @discord.ui.button(label="警告", style=discord.ButtonStyle.secondary)
203
- async def warn_button(self, interaction: discord.Interaction, button: discord.ui.Button):
204
- logger.info(f"{interaction.user} 使用 GUI 警告 {self.member}")
205
- try:
206
- await self.member.send(f"你在伺服器 {interaction.guild.name} 被警告。請注意言行。")
207
- except:
208
- pass
209
- await interaction.response.send_message(f"{self.member.mention} 已被警告。", ephemeral=True)
203
+ @discord.ui.button(label="警告", style=discord.ButtonStyle.secondary)
204
+ async def warn_button(self, interaction: discord.Interaction, button: discord.ui.Button):
205
+ await self.member.send(f"你在伺服器 {interaction.guild.name} 被警告。")
206
+ await interaction.response.send_message(f"{self.member.mention} 已被警告。", ephemeral=True)
210
207
 
211
- @discord.ui.button(label="閉嘴 60 秒", style=discord.ButtonStyle.primary)
212
- async def timeout_button(self, interaction: discord.Interaction, button: discord.ui.Button):
213
- try:
208
+ @discord.ui.button(label="閉嘴 60 秒", style=discord.ButtonStyle.primary)
209
+ async def timeout_button(self, interaction: discord.Interaction, button: discord.ui.Button):
214
210
  until = datetime.utcnow() + timedelta(seconds=60)
215
211
  await self.member.timeout(until, reason="由管理員 GUI 操作禁言")
216
212
  await interaction.response.send_message(f"{self.member.mention} 已被禁言 60 秒。", ephemeral=True)
217
- except Exception as e:
218
- await interaction.response.send_message(f"禁言失敗:{e}", ephemeral=True)
219
- @discord.ui.button(label="踢出", style=discord.ButtonStyle.danger)
220
- async def kick_button(self, interaction: discord.Interaction, button: discord.ui.Button):
221
- logger.info(f"{interaction.user} 使用 GUI 踢出 {self.member}")
222
- try:
223
- await self.member.kick(reason="由管理員 GUI 操作踢出")
224
- await interaction.response.send_message(f"{self.member.mention} 已被踢出。", ephemeral=True)
225
- except Exception as e:
226
- await interaction.response.send_message(f"踢出失敗:{e}", ephemeral=True)
227
213
 
228
- @discord.ui.button(label="封鎖", style=discord.ButtonStyle.danger)
229
- async def ban_button(self, interaction: discord.Interaction, button: discord.ui.Button):
230
- logger.info(f"{interaction.user} 使用 GUI 封鎖 {self.member}")
231
- try:
232
- await self.member.ban(reason="由管理員 GUI 操作封鎖")
233
- await interaction.response.send_message(f"{self.member.mention} 已被封鎖。", ephemeral=True)
234
- except Exception as e:
235
- await interaction.response.send_message(f"封鎖失敗:{e}", ephemeral=True)
236
-
237
- # ─── 啟動 ───────────────────────────────────────────────────────────────────
238
-
239
- try:
240
- logger.info("正在啟動機器人...")
241
- bot.run(token)
242
- except discord.LoginFailure:
243
- logger.error("Token 無效,請重新確認。")
244
- except Exception as e:
245
- logger.exception(f"發生錯誤:{e}")
214
+ @discord.ui.button(label="踢出", style=discord.ButtonStyle.danger)
215
+ async def kick_button(self, interaction: discord.Interaction, button: discord.ui.Button):
216
+ await self.member.kick(reason="由管理員 GUI 操作踢出")
217
+ await interaction.response.send_message(f"{self.member.mention} 已被踢出。", ephemeral=True)
246
218
 
219
+ @discord.ui.button(label="封鎖", style=discord.ButtonStyle.danger)
220
+ async def ban_button(self, interaction: discord.Interaction, button: discord.ui.Button):
221
+ await self.member.ban(reason="由管理員 GUI 操作封鎖")
222
+ await interaction.response.send_message(f"{self.member.mention} 已被封鎖。", ephemeral=True)
247
223
 
248
- if __name__ == "__main__":
249
- run()
250
- # ─── Shell 命令 ──────────────────────────────────────────────────────────────
224
+ # ─── Shell 控制 ──────────────────────────────────────────────────────────────
251
225
  def shell(shell_command):
226
+ global OWNER_ID, LOG_CHANNEL_ID, token, bot
227
+ logger.info(f"[Shell 輸入] {shell_command}")
228
+ if bot and bot.is_ready():
229
+ bot.loop.create_task(DiscordLogHandler(bot, LOG_CHANNEL_ID).send_log(f"[Shell] `{shell_command}`"))
230
+
252
231
  if shell_command == "!!token-reset":
253
- token = input("請輸入新的 Discord Bot Token:\n> ").strip()
232
+ token = input("請輸入新的 Token:\n> ").strip()
254
233
  bot._token = token
255
- logger.info("Token 已更新。")
256
- print("Token 已更新。請重新啟動機器人以應用新 Token。")
257
- logger.info(f"{interaction.user} 嘗試關閉機器人")
258
- bot.close()
234
+ logger.info("Token 已更新。請重啟機器人。")
259
235
  elif shell_command == "!!token-display":
260
236
  print(f"當前 Token: {token}")
261
- elif shell_command == "!!help":
262
- print("可用的 shell 命令:")
263
- print("!!token-reset - 重設 Bot Token")
264
- print("!!token-display - 顯示當前 Bot Token")
265
- print("!!exit - 關閉機器人")
266
- print("!!id-reset-owner - 重設擁有者 ID")
267
- print("!!id-display-owner - 顯示當前擁有者 ID")
268
- print("!!id-reset-logch - 重設 Log 頻道 ID")
269
- print("!!id-display-logch - 顯示當前 Log 頻道 ID")
270
- elif shell_command == "exit":
271
- print("正在關閉機器人...")
272
- logger.info(f"{interaction.user} 嘗試關閉機器人")
273
- bot.close()
274
- elif shell_command == "!!id-reset-owner":
275
- global OWNER_ID
276
- OWNER_ID = int(input("請輸入新的擁有者 ID:\n> ").strip())
277
- logger.info(f"擁有者 ID 已更新為 {OWNER_ID}")
278
- print(f"擁有者 ID 已更新為 {OWNER_ID}")
279
237
  elif shell_command == "!!id-display-owner":
280
- print(f"當前擁有者 ID: {OWNER_ID}")
238
+ print(f"擁有者 ID: {OWNER_ID}")
239
+ elif shell_command == "!!id-reset-owner":
240
+ OWNER_ID = int(input("新的 OWNER_ID:\n> "))
241
+ logger.info(f"OWNER_ID 更新為 {OWNER_ID}")
242
+ elif shell_command == "!!id-display-logch":
243
+ print(f"Log 頻道 ID: {LOG_CHANNEL_ID}")
281
244
  elif shell_command == "!!id-reset-logch":
282
- global LOG_CHANNEL_ID
283
- LOG_CHANNEL_ID = int(input("請輸入新的 Log 頻道 ID:\n> ").strip())
284
- logger.info(f"Log 頻道 ID 已更新為 {LOG_CHANNEL_ID}")
285
- print(f"Log 頻道 ID 已更新為 {LOG_CHANNEL_ID}")
286
- elif shell_command == "id-display-logch":
287
- print(f"當前 Log 頻道 ID: {LOG_CHANNEL_ID}")
245
+ LOG_CHANNEL_ID = int(input("新的 LOG_CHANNEL_ID:\n> "))
246
+ logger.info(f"LOG_CHANNEL_ID 更新為 {LOG_CHANNEL_ID}")
247
+ elif shell_command == "!!help":
248
+ print("可用指令:!!token-display / !!token-reset / !!id-reset-owner / !!id-display-owner / !!exit")
249
+ elif shell_command == "!!exit":
250
+ print("正在關閉機器人...")
251
+ logger.info("Shell 關閉機器人。")
252
+ if bot:
253
+ bot.loop.create_task(bot.close())
288
254
  else:
289
- interaction.response.send_message(shell_command, ephemeral=True)
290
- print(f"未知的 shell 命令:{shell_command}")
291
- print("請使用 !!help 查看可用命令。")
292
- while True:
293
- shell_command = input("請輸入 shell 命令(輸入 !!help 查看可用命令):\n> ").strip()
294
- shell(shell_command)
255
+ print(f"未知的指令:{shell_command}")
256
+
257
+ # ─── 啟動程式 ────────────────────────────────────────────────────────────────
258
+ if __name__ == "__main__":
259
+ run()
260
+ while True:
261
+ try:
262
+ shell_command = input("請輸入 shell 命令(輸入 !!help 查看):\n> ").strip()
263
+ shell(shell_command)
264
+ except (KeyboardInterrupt, EOFError):
265
+ print("E:Shell 已關閉")
266
+ break
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dcchbot
3
- Version: 1.8
3
+ Version: 1.8.1
4
4
  Summary: 一個簡單的中文 Discord 管理機器人,支援 GUI 按鈕封鎖/禁言/警告
5
5
  Author-email: I_am_from_taiwan <102109040j@gmail.com>
6
6
  License: MIT
@@ -0,0 +1,9 @@
1
+ dcchbot/__init__.py,sha256=zp5WAMYJ8lMGsJsMRvHCjvTXVR426Satbz_orCtk990,105
2
+ dcchbot/__main__.py,sha256=5FwoJspcKFt5_1AlXoxlWROiQSp9wgnFEltU6ufz9QE,30
3
+ dcchbot/main.py,sha256=lZBbrwW73C_TvL4mlt5CHU1nD5DjRjTOHFW8QRiOkKY,14220
4
+ dcchbot-1.8.1.dist-info/licenses/LICENSE,sha256=l3hyIOCB7NYorC-bjV5yZM0PgAJbMgAWNLE644dR7H4,1065
5
+ dcchbot-1.8.1.dist-info/METADATA,sha256=1Rwh5fL_ZiwPO-Ft6XSIalVJ2G9_-YWwy382_MN1S3w,446
6
+ dcchbot-1.8.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ dcchbot-1.8.1.dist-info/entry_points.txt,sha256=90T16CGc_Tx-4pFaLCcbuuh7Vi9l4gsLovBkydqxP9Y,45
8
+ dcchbot-1.8.1.dist-info/top_level.txt,sha256=jiDTz8UmwZgXN9KzokwDRYhoWxsVmWcnqmrANeTFMck,8
9
+ dcchbot-1.8.1.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- dcchbot/__init__.py,sha256=brxuwAfpNYUvVMswuBqeS1saX84TyisHybbdyMpGZos,103
2
- dcchbot/__main__.py,sha256=5FwoJspcKFt5_1AlXoxlWROiQSp9wgnFEltU6ufz9QE,30
3
- dcchbot/main.py,sha256=23218BZjZ7DJ6_vrghv1kMgLTovyfttdn4fkMWKPo5c,15825
4
- dcchbot-1.8.dist-info/licenses/LICENSE,sha256=l3hyIOCB7NYorC-bjV5yZM0PgAJbMgAWNLE644dR7H4,1065
5
- dcchbot-1.8.dist-info/METADATA,sha256=xH5FZDAePfsgE8RK9AVkegcb2seEXw8zUiKgmOA5V7Y,444
6
- dcchbot-1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- dcchbot-1.8.dist-info/entry_points.txt,sha256=90T16CGc_Tx-4pFaLCcbuuh7Vi9l4gsLovBkydqxP9Y,45
8
- dcchbot-1.8.dist-info/top_level.txt,sha256=jiDTz8UmwZgXN9KzokwDRYhoWxsVmWcnqmrANeTFMck,8
9
- dcchbot-1.8.dist-info/RECORD,,
File without changes