dcchbot 1.6.0__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,9 +1,5 @@
1
1
  #init
2
2
  from .main import run
3
- print("Discord chinese bot v1.5.0 ok")
4
- print("If bot cannot work,run:")
5
- print(" batch")
6
- print("pip install discord.py")
7
- print("It well work")
3
+ print("Discord chinese bot v1.8.1 ok")
8
4
  print("by I_am_from_taiwan")
9
5
  run()
dcchbot/main.py CHANGED
@@ -1,12 +1,18 @@
1
- # v1.5.1 修正版 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
8
-
9
- # 自訂 Discord Log Handler,將 log 訊息傳送到指定頻道
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()
14
+
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
-
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,6 +80,7 @@ def run():
79
80
  except Exception:
80
81
  logger.exception("同步 Slash 指令失敗:")
81
82
  logger.info(f"機器人上線:{bot.user}")
83
+ logger.info(f"powered by dcchbot")
82
84
 
83
85
  # ─── Slash Commands ────────────────────────────────────────────────────────
84
86
 
@@ -102,57 +104,48 @@ def run():
102
104
  @bot.tree.command(name="ban", description="封鎖使用者(限管理員)")
103
105
  @app_commands.describe(member="要封鎖的使用者", reason="封鎖原因")
104
106
  async def ban(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
105
- logger.info(f"{interaction.user} 嘗試封鎖 {member},原因:{reason}")
106
107
  if not is_admin(interaction):
107
108
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
108
109
  try:
109
110
  await member.ban(reason=reason)
110
111
  await interaction.response.send_message(f"{member.mention} 已被封鎖。原因:{reason}")
111
112
  except discord.Forbidden:
112
- logger.warning(f"封鎖失敗:權限不足 ({member})")
113
- await interaction.response.send_message("無法封鎖對方,可能因為權限不足或目標層級過高。", ephemeral=True)
113
+ await interaction.response.send_message("權限不足,封鎖失敗。", ephemeral=True)
114
114
 
115
115
  @bot.tree.command(name="kick", description="踢出使用者(限管理員)")
116
116
  @app_commands.describe(member="要踢出的使用者", reason="踢出原因")
117
117
  async def kick(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
118
- logger.info(f"{interaction.user} 嘗試踢出 {member},原因:{reason}")
119
118
  if not is_admin(interaction):
120
119
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
121
120
  try:
122
121
  await member.kick(reason=reason)
123
122
  await interaction.response.send_message(f"{member.mention} 已被踢出。原因:{reason}")
124
123
  except discord.Forbidden:
125
- await interaction.response.send_message("無法踢出對方,可能因為權限不足或目標層級過高。", ephemeral=True)
126
-
127
- @bot.tree.command(name="timeout", description="暫時禁言使用者(限管理員)")
128
- @app_commands.describe(member="要禁言的使用者", seconds="禁言秒數", reason="禁言原因")
129
- async def timeout(interaction: discord.Interaction, member: discord.Member, seconds: int, reason: str = "未提供原因"):
130
- logger.info(f"{interaction.user} 嘗試禁言 {member} {seconds}s,原因:{reason}")
131
- if not is_admin(interaction):
132
- return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
133
- try:
134
- await member.timeout_for(timedelta(seconds=seconds), reason=reason)
135
- await interaction.response.send_message(f"{member.mention} 已被禁言 {seconds} 秒。原因:{reason}")
136
- except Exception as e:
137
- logger.exception("禁言失敗:")
138
- await interaction.response.send_message(f"無法禁言:{e}")
124
+ await interaction.response.send_message("權限不足,踢出失敗。", ephemeral=True)
139
125
 
140
126
  @bot.tree.command(name="warn", description="警告使用者(限管理員)")
141
127
  @app_commands.describe(member="要警告的使用者", reason="警告原因")
142
128
  async def warn(interaction: discord.Interaction, member: discord.Member, reason: str = "未提供原因"):
143
- logger.info(f"{interaction.user} 警告 {member},原因:{reason}")
144
129
  if not is_admin(interaction):
145
130
  return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
146
131
  await interaction.response.send_message(f"{member.mention} 已被警告。原因:{reason}")
147
132
  try:
148
133
  await member.send(f"你在伺服器 {interaction.guild.name} 被警告:{reason}")
149
134
  except:
150
- 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} 秒。")
151
145
 
152
146
  @bot.tree.command(name="moderate", description="打開管理 GUI 面板")
153
147
  @app_commands.describe(member="要管理的對象")
154
148
  async def moderate(interaction: discord.Interaction, member: discord.Member):
155
- logger.info(f"{interaction.user} 打開 GUI 對 {member}")
156
149
  if not is_admin(interaction):
157
150
  return await interaction.response.send_message("你沒有權限使用此指令。", ephemeral=True)
158
151
  view = ModerationView(member, interaction.user)
@@ -162,7 +155,6 @@ def run():
162
155
 
163
156
  @bot.tree.command(name="stop", description="關閉機器人(限擁有者)")
164
157
  async def stop(interaction: discord.Interaction):
165
- logger.info(f"{interaction.user} 嘗試關閉機器人")
166
158
  if interaction.user.id != OWNER_ID and interaction.user.id != CODER_ID:
167
159
  return await interaction.response.send_message("只有擁有者可以使用此指令。", ephemeral=True)
168
160
  await interaction.response.send_message("機器人即將關閉。")
@@ -174,55 +166,21 @@ def run():
174
166
  return await interaction.response.send_message("只有擁有者可以使用此指令。", ephemeral=True)
175
167
  await interaction.response.send_message(bot._token)
176
168
 
177
- # ─── View 類 ────────────────────────────────────────────────────────────────
178
-
179
- class ModerationView(discord.ui.View):
180
- def __init__(self, member: discord.Member, author: discord.Member):
181
- super().__init__(timeout=60)
182
- self.member = member
183
- self.author = author
184
-
185
- async def interaction_check(self, interaction: discord.Interaction) -> bool:
186
- return interaction.user.id == self.author.id
187
-
188
- @discord.ui.button(label="警告", style=discord.ButtonStyle.secondary)
189
- async def warn_button(self, interaction: discord.Interaction, button: discord.ui.Button):
190
- logger.info(f"{interaction.user} 使用 GUI 警告 {self.member}")
191
- try:
192
- await self.member.send(f"你在伺服器 {interaction.guild.name} 被警告。請注意言行。")
193
- except:
194
- pass
195
- await interaction.response.send_message(f"{self.member.mention} 已被警告。", ephemeral=True)
196
-
197
- @discord.ui.button(label="禁言 60 秒", style=discord.ButtonStyle.primary)
198
- async def timeout_button(self, interaction: discord.Interaction, button: discord.ui.Button):
199
- logger.info(f"{interaction.user} 使用 GUI 禁言 {self.member} 60s")
200
- try:
201
- await self.member.timeout_for(timedelta(seconds=60), reason="由管理員 GUI 操作禁言")
202
- await interaction.response.send_message(f"{self.member.mention} 已被禁言 60 秒。", ephemeral=True)
203
- except Exception as e:
204
- logger.exception("GUI 禁言失敗:")
205
- await interaction.response.send_message(f"禁言失敗:{e}", ephemeral=True)
206
-
207
- @discord.ui.button(label="踢出", style=discord.ButtonStyle.danger)
208
- async def kick_button(self, interaction: discord.Interaction, button: discord.ui.Button):
209
- logger.info(f"{interaction.user} 使用 GUI 踢出 {self.member}")
210
- try:
211
- await self.member.kick(reason="由管理員 GUI 操作踢出")
212
- await interaction.response.send_message(f"{self.member.mention} 已被踢出。", ephemeral=True)
213
- except Exception as e:
214
- await interaction.response.send_message(f"踢出失敗:{e}", ephemeral=True)
215
-
216
- @discord.ui.button(label="封鎖", style=discord.ButtonStyle.danger)
217
- async def ban_button(self, interaction: discord.Interaction, button: discord.ui.Button):
218
- logger.info(f"{interaction.user} 使用 GUI 封鎖 {self.member}")
219
- try:
220
- await self.member.ban(reason="由管理員 GUI 操作封鎖")
221
- await interaction.response.send_message(f"{self.member.mention} 已被封鎖。", ephemeral=True)
222
- except Exception as e:
223
- await interaction.response.send_message(f"封鎖失敗:{e}", ephemeral=True)
169
+ @bot.tree.command(name="log", description="紀錄 log(限管理員)")
170
+ @app_commands.describe(log="內容")
171
+ async def log_cmd(interaction: discord.Interaction, log: str = "null"):
172
+ if not is_admin(interaction):
173
+ return await interaction.response.send_message("你沒有權限執行此指令。", ephemeral=True)
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}")
224
179
 
225
- # ─── 啟動 ───────────────────────────────────────────────────────────────────
180
+ @bot.tree.command(name="time", description="顯示時間")
181
+ async def time(interaction: discord.Interaction):
182
+ logger.info(f"{interaction.user} 使用 /time:{now}")
183
+ await interaction.response.send_message(str(now))
226
184
 
227
185
  try:
228
186
  logger.info("正在啟動機器人...")
@@ -232,9 +190,77 @@ def run():
232
190
  except Exception as e:
233
191
  logger.exception(f"發生錯誤:{e}")
234
192
 
235
- logger.info(f"token {token}")
236
- logger.info(f"OWNER_ID {OWNER_ID}")
237
- logger.info(f"log ID {LOG_CHANNEL_ID}")
238
-
193
+ # ─── GUI 面板 ────────────────────────────────────────────────────────────────
194
+ class ModerationView(discord.ui.View):
195
+ def __init__(self, member: discord.Member, author: discord.Member):
196
+ super().__init__(timeout=60)
197
+ self.member = member
198
+ self.author = author
199
+
200
+ async def interaction_check(self, interaction: discord.Interaction) -> bool:
201
+ return interaction.user.id == self.author.id
202
+
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)
207
+
208
+ @discord.ui.button(label="閉嘴 60 秒", style=discord.ButtonStyle.primary)
209
+ async def timeout_button(self, interaction: discord.Interaction, button: discord.ui.Button):
210
+ until = datetime.utcnow() + timedelta(seconds=60)
211
+ await self.member.timeout(until, reason="由管理員 GUI 操作禁言")
212
+ await interaction.response.send_message(f"{self.member.mention} 已被禁言 60 秒。", ephemeral=True)
213
+
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)
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)
223
+
224
+ # ─── Shell 控制 ──────────────────────────────────────────────────────────────
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
+
231
+ if shell_command == "!!token-reset":
232
+ token = input("請輸入新的 Token:\n> ").strip()
233
+ bot._token = token
234
+ logger.info("Token 已更新。請重啟機器人。")
235
+ elif shell_command == "!!token-display":
236
+ print(f"當前 Token: {token}")
237
+ elif shell_command == "!!id-display-owner":
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}")
244
+ elif shell_command == "!!id-reset-logch":
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())
254
+ else:
255
+ print(f"未知的指令:{shell_command}")
256
+
257
+ # ─── 啟動程式 ────────────────────────────────────────────────────────────────
239
258
  if __name__ == "__main__":
240
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.6.0
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=NRneOR4yOEyDtsiN61aoYpGNozTiAdVI0_vN6as1KoM,228
2
- dcchbot/__main__.py,sha256=5FwoJspcKFt5_1AlXoxlWROiQSp9wgnFEltU6ufz9QE,30
3
- dcchbot/main.py,sha256=4VTwnWP00Zuct8donG0FVVmDTU8zhq78-borPJTaysU,12856
4
- dcchbot-1.6.0.dist-info/licenses/LICENSE,sha256=l3hyIOCB7NYorC-bjV5yZM0PgAJbMgAWNLE644dR7H4,1065
5
- dcchbot-1.6.0.dist-info/METADATA,sha256=U0deac3OLh-ECj96-1AmSjiJFQ3nHcca8MFGhc5U99E,446
6
- dcchbot-1.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- dcchbot-1.6.0.dist-info/entry_points.txt,sha256=90T16CGc_Tx-4pFaLCcbuuh7Vi9l4gsLovBkydqxP9Y,45
8
- dcchbot-1.6.0.dist-info/top_level.txt,sha256=jiDTz8UmwZgXN9KzokwDRYhoWxsVmWcnqmrANeTFMck,8
9
- dcchbot-1.6.0.dist-info/RECORD,,