提高了bot用户体验

This commit is contained in:
dela
2026-01-06 17:09:15 +08:00
parent 21f8b1ba9d
commit f4ecbac1bc
3 changed files with 98 additions and 37 deletions

View File

@@ -21,4 +21,4 @@ echo ""
echo "现在你可以运行:" echo "现在你可以运行:"
echo " checker # 运行命令行工具" echo " checker # 运行命令行工具"
echo " python -m checker # 或使用模块方式" echo " python -m checker # 或使用模块方式"
echo " uv run python -m checker # 使用uv运行" echo " uv run python -m checker.bot.main # 使用uv运行"

View File

@@ -27,34 +27,52 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"1. <b>/chk</b> - 检测卡片\n" "1. <b>/chk</b> - 检测卡片\n"
" <code>/chk cc|mm|yy|cvv</code>\n\n" " <code>/chk cc|mm|yy|cvv</code>\n\n"
"2. <b>/gen</b> - 生成卡片\n" "2. <b>/gen</b> - 生成卡片\n"
" <code>/gen 10 536737xxxx</code> (生成10张)\n" " <code>/gen 536737xxxx</code> (默认10张)\n"
" <code>/gen 10 536737xxxx /chk</code> (生成并检测)" " <code>/gen 20 536737xxxx</code> (生成20张)\n"
" <code>/gen 536737xxxx /chk</code> (生成并检测)"
) )
async def gen_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: async def gen_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""响应 /gen 命令""" """响应 /gen 命令"""
# 格式: /gen <count> <pattern> [/chk] # 格式: /gen [count] <pattern> [/chk]
if not context.args or len(context.args) < 2: # 默认数量为 10
if not context.args or len(context.args) < 1:
await update.message.reply_html( await update.message.reply_html(
"❌ <b>格式错误</b>\n\n" "❌ <b>格式错误</b>\n\n"
"用法:\n" "用法:\n"
"<code>/gen 10 536737xxxxxxxxxx</code>\n" "<code>/gen 536737xxxxxxxxxx</code> (默认10张)\n"
"<code>/gen 10 536737xxxxxxxxxx /chk</code>" "<code>/gen 20 536737xxxxxxxxxx</code> (指定数量)\n"
"<code>/gen 536737xxxxxxxxxx /chk</code> (生成并检测)"
) )
return return
try: # 智能解析参数
count = int(context.args[0]) count = 10 # 默认数量
pattern = context.args[1] pattern = None
except ValueError:
await update.message.reply_text("❌ 数量必须是数字。")
return
# 检查是否有 /chk
do_check = False do_check = False
if len(context.args) > 2 and '/chk' in context.args[2:]:
# 检查是否有 /chk 参数
args_without_chk = [arg for arg in context.args if arg != '/chk']
if '/chk' in context.args:
do_check = True do_check = True
# 解析数量和模式
if len(args_without_chk) == 1:
# /gen <pattern>
pattern = args_without_chk[0]
elif len(args_without_chk) >= 2:
# 尝试第一个参数是否为数字
try:
count = int(args_without_chk[0])
pattern = args_without_chk[1]
except ValueError:
# 如果第一个参数不是数字,则当作模式,使用默认数量
pattern = args_without_chk[0]
if not pattern:
await update.message.reply_text("❌ 请提供卡片模式。")
return
# 限制生成数量 # 限制生成数量
if count > 1000: if count > 1000:
await update.message.reply_text("❌ 一次最多生成 1000 张卡片。") await update.message.reply_text("❌ 一次最多生成 1000 张卡片。")
@@ -143,7 +161,8 @@ async def process_input_text(update: Update, context: ContextTypes.DEFAULT_TYPE,
"dead": 0, "dead": 0,
"unknown": 0, "unknown": 0,
"total": len(cards), "total": len(cards),
"checked": 0 "checked": 0,
"results": [] # 存储所有检测结果
} }
# 4. 创建并发任务 # 4. 创建并发任务
@@ -156,13 +175,21 @@ async def process_input_text(update: Update, context: ContextTypes.DEFAULT_TYPE,
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
# 5. 最终报告 # 5. 最终报告
report = ( report_lines = [
f"<b>🏁 检测完成</b>\n\n" f"<b>🏁 检测完成</b>\n",
f"Total: {stats['total']}\n" f"Total: {stats['total']}",
f"Live: {stats['live']}\n" f"Live: {stats['live']}",
f"Dead: {stats['dead']}\n" f"Dead: {stats['dead']}",
f"Unknown: {stats['unknown']} ⚠️" f"Unknown: {stats['unknown']} ⚠️\n"
) ]
# 添加所有卡片的详细结果
if stats['results']:
report_lines.append("<b>详细结果:</b>")
for result_info in stats['results']:
report_lines.append(result_info)
report = "\n".join(report_lines)
await status_msg.edit_text(report, parse_mode=ParseMode.HTML) await status_msg.edit_text(report, parse_mode=ParseMode.HTML)
async def process_card( async def process_card(
@@ -189,17 +216,29 @@ async def process_card(
stats["checked"] += 1 stats["checked"] += 1
# 格式化结果信息
card_info = f"<code>{card.formatted}</code>"
if result.status == CheckStatus.LIVE: if result.status == CheckStatus.LIVE:
stats["live"] += 1 stats["live"] += 1
result_line = f"{card_info} - {result.message}"
stats["results"].append(result_line)
await send_live_alert(update, result) await send_live_alert(update, result)
elif result.status == CheckStatus.DEAD: elif result.status == CheckStatus.DEAD:
stats["dead"] += 1 stats["dead"] += 1
result_line = f"{card_info} - {result.message}"
stats["results"].append(result_line)
else: else:
stats["unknown"] += 1 stats["unknown"] += 1
result_line = f"{card_info} - {result.message} ⚠️"
stats["results"].append(result_line)
except Exception as e: except Exception as e:
logger.error(f"Error checking card {card.formatted}: {e}") logger.error(f"Error checking card {card.formatted}: {e}")
stats["unknown"] += 1 stats["unknown"] += 1
card_info = f"<code>{card.formatted}</code>"
result_line = f"{card_info} - Error: {str(e)} ⚠️"
stats["results"].append(result_line)
finally: finally:
session.close() session.close()

View File

@@ -67,21 +67,22 @@ class CardGenerator:
def parse_date_cvv(self, card_num: str, m_req: Optional[str], y_req: Optional[str], c_req: Optional[str]) -> Tuple[str, str, str]: def parse_date_cvv(self, card_num: str, m_req: Optional[str], y_req: Optional[str], c_req: Optional[str]) -> Tuple[str, str, str]:
""" """
处理日期和CVV的占位符逻辑 处理日期和CVV的占位符逻辑
支持 (m), (y), (cvv), rnd 或任何非纯数字的值作为随机标记
""" """
# --- Month --- # --- Month ---
if m_req in ['(m)', 'rnd', '', None]: if self._is_random_placeholder(m_req):
month = str(random.randint(1, 12)).zfill(2) month = str(random.randint(1, 12)).zfill(2)
else: else:
month = m_req.strip() month = m_req.strip()
# --- Year --- # --- Year ---
if y_req in ['(y)', 'rnd', '', None]: if self._is_random_placeholder(y_req):
year = str(self.current_year + random.randint(2, 5)) year = str(self.current_year + random.randint(2, 5))
else: else:
year = y_req.strip() year = y_req.strip()
# --- CVV --- # --- CVV ---
if c_req in ['(cvv)', 'rnd', '', None]: if self._is_random_placeholder(c_req):
if card_num.startswith(('34', '37')): if card_num.startswith(('34', '37')):
cvv = str(random.randint(1102, 9999)) cvv = str(random.randint(1102, 9999))
else: else:
@@ -91,6 +92,27 @@ class CardGenerator:
return month, year, cvv return month, year, cvv
def _is_random_placeholder(self, value: Optional[str]) -> bool:
"""
判断值是否为随机占位符
支持: None, '', '(m)', '(y)', '(cvv)', 'rnd', 或任何非纯数字的值(如 'xxx', 'abc' 等)
"""
if value is None or value.strip() == '':
return True
value = value.strip()
# 已知的占位符
known_placeholders = ['(m)', '(y)', '(cvv)', 'rnd']
if value in known_placeholders:
return True
# 如果是非纯数字的字符串,视为占位符
if not value.isdigit():
return True
return False
def process_line(self, raw_input: str, count: int = 1) -> List[str]: def process_line(self, raw_input: str, count: int = 1) -> List[str]:
""" """
生成指定数量的卡片 生成指定数量的卡片