初始化多平台机器人部署项目 - Telegram/Discord/QQ资源搜索机器人
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
# Discord机器人配置
|
||||
DISCORD_TOKEN=your_discord_bot_token_here
|
||||
|
||||
# 资源数据库路径(默认使用Telegram采集的数据库)
|
||||
# RESOURCE_DB_PATH=F:\开源项目\telegram-resource-collector\web_collected.db
|
||||
@@ -0,0 +1,436 @@
|
||||
"""
|
||||
Discord资源搜索机器人 - 独立数据库版
|
||||
功能:全局资源搜索、群管理、资源统计、独立数据库
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import sqlite3
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# 加载配置
|
||||
load_dotenv()
|
||||
DISCORD_TOKEN = os.getenv("DISCORD_TOKEN", "")
|
||||
|
||||
# 独立数据库路径(Discord机器人自己的数据库)
|
||||
BOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DB_PATH = os.path.join(BOT_DIR, "discord_resources.db")
|
||||
|
||||
# 每页显示数量
|
||||
PAGE_SIZE = 8
|
||||
|
||||
|
||||
# ========== 数据库初始化 ==========
|
||||
def init_db():
|
||||
"""初始化独立数据库"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
# 资源表
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS resources (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
tg_link TEXT DEFAULT '',
|
||||
source TEXT DEFAULT '',
|
||||
keyword TEXT DEFAULT '',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
# 搜索记录表
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS search_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER,
|
||||
keyword TEXT,
|
||||
result_count INTEGER,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
# 群配置表
|
||||
c.execute("""
|
||||
CREATE TABLE IF NOT EXISTS group_config (
|
||||
guild_id INTEGER PRIMARY KEY,
|
||||
guild_name TEXT,
|
||||
welcome_enabled INTEGER DEFAULT 1,
|
||||
search_enabled INTEGER DEFAULT 1,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"✅ 数据库初始化: {DB_PATH}")
|
||||
|
||||
|
||||
# ========== 资源搜索功能 ==========
|
||||
def search_resources(keyword, limit=PAGE_SIZE, offset=0):
|
||||
"""从独立数据库搜索资源"""
|
||||
if not os.path.exists(DB_PATH):
|
||||
init_db()
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
conn.row_factory = sqlite3.Row
|
||||
c = conn.cursor()
|
||||
|
||||
query = """
|
||||
SELECT id, title, tg_link, source, keyword, created_at
|
||||
FROM resources
|
||||
WHERE title LIKE ? OR keyword LIKE ? OR source LIKE ?
|
||||
ORDER BY (tg_link != '') DESC, created_at DESC
|
||||
LIMIT ? OFFSET ?
|
||||
"""
|
||||
like_keyword = f"%{keyword}%"
|
||||
c.execute(query, (like_keyword, like_keyword, like_keyword, limit, offset))
|
||||
results = [dict(row) for row in c.fetchall()]
|
||||
|
||||
c.execute("""
|
||||
SELECT COUNT(*) FROM resources
|
||||
WHERE title LIKE ? OR keyword LIKE ? OR source LIKE ?
|
||||
""", (like_keyword, like_keyword, like_keyword))
|
||||
total = c.fetchone()[0]
|
||||
|
||||
conn.close()
|
||||
return results, total
|
||||
|
||||
|
||||
def add_resource(title, tg_link="", source="", keyword=""):
|
||||
"""添加资源到数据库"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT OR IGNORE INTO resources (title, tg_link, source, keyword)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""", (title, tg_link, source, keyword))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_stats():
|
||||
"""获取数据库统计"""
|
||||
if not os.path.exists(DB_PATH):
|
||||
init_db()
|
||||
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute("SELECT COUNT(*) FROM resources")
|
||||
total = c.fetchone()[0]
|
||||
|
||||
c.execute("SELECT COUNT(*) FROM resources WHERE tg_link != ''")
|
||||
with_link = c.fetchone()[0]
|
||||
|
||||
c.execute("SELECT COUNT(*) FROM search_log")
|
||||
search_count = c.fetchone()[0]
|
||||
|
||||
conn.close()
|
||||
return {"total": total, "with_link": with_link, "search_count": search_count}
|
||||
|
||||
|
||||
def log_search(user_id, keyword, result_count):
|
||||
"""记录搜索日志"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT INTO search_log (user_id, keyword, result_count)
|
||||
VALUES (?, ?, ?)
|
||||
""", (user_id, keyword, result_count))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
# ========== 格式化输出 ==========
|
||||
def format_results(results, keyword, total, page=0):
|
||||
"""格式化搜索结果"""
|
||||
lines = []
|
||||
lines.append(f"🔍 搜索「{keyword}」共找到 {total} 条结果")
|
||||
lines.append(f"📄 第 {page+1} 页 / 共 {(total + PAGE_SIZE - 1) // PAGE_SIZE} 页")
|
||||
lines.append("")
|
||||
|
||||
for i, res in enumerate(results, 1):
|
||||
idx = page * PAGE_SIZE + i
|
||||
title = res.get("title", "")[:80]
|
||||
tg_link = res.get("tg_link", "")
|
||||
source = res.get("source", "")
|
||||
|
||||
link_icon = "📎" if tg_link else "🔍"
|
||||
lines.append(f"{idx}. {link_icon} {title}")
|
||||
|
||||
if tg_link:
|
||||
lines.append(f" 🔗 {tg_link}")
|
||||
|
||||
if source:
|
||||
lines.append(f" 📡 来源: {source}")
|
||||
|
||||
lines.append("")
|
||||
|
||||
if total == 0:
|
||||
lines = [f"❌ 未找到与「{keyword}」相关的资源", "", "💡 试试其他关键词"]
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ========== Discord机器人配置 ==========
|
||||
intents = discord.Intents.default()
|
||||
intents.message_content = True
|
||||
intents.members = True
|
||||
|
||||
bot = commands.Bot(command_prefix='!', intents=intents, help_command=None)
|
||||
|
||||
|
||||
# ========== 事件处理 ==========
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
"""机器人启动完成"""
|
||||
init_db()
|
||||
print(f'✅ Discord机器人已登录: {bot.user}')
|
||||
print(f'📊 已连接 {len(bot.guilds)} 个服务器')
|
||||
print(f'💾 数据库: {DB_PATH}')
|
||||
await bot.change_presence(activity=discord.Game(name="资源搜索 | 发关键词自动搜索"))
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_guild_join(guild):
|
||||
"""加入新服务器"""
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT OR IGNORE INTO group_config (guild_id, guild_name)
|
||||
VALUES (?, ?)
|
||||
""", (guild.id, guild.name))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print(f"➕ 加入新服务器: {guild.name} ({guild.id})")
|
||||
|
||||
|
||||
@bot.event
|
||||
async def on_member_join(member):
|
||||
"""新成员加入欢迎"""
|
||||
# 检查是否启用欢迎
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT welcome_enabled FROM group_config WHERE guild_id = ?", (member.guild.id,))
|
||||
result = c.fetchone()
|
||||
conn.close()
|
||||
|
||||
if result and result[0] == 0:
|
||||
return
|
||||
|
||||
# 查找欢迎频道
|
||||
welcome_channel = None
|
||||
for channel in member.guild.text_channels:
|
||||
if 'welcome' in channel.name.lower() or '欢迎' in channel.name or 'general' in channel.name.lower():
|
||||
welcome_channel = channel
|
||||
break
|
||||
|
||||
if not welcome_channel and member.guild.text_channels:
|
||||
welcome_channel = member.guild.text_channels[0]
|
||||
|
||||
if welcome_channel:
|
||||
welcome_msg = f"""
|
||||
👋 欢迎 **{member.mention}** 加入 **{member.guild.name}**!
|
||||
|
||||
📋 本机器人功能:
|
||||
• 直接发送关键词即可搜索资源
|
||||
• `!search 关键词` - 搜索资源
|
||||
• `!stats` - 查看资源库统计
|
||||
• `!help` - 查看帮助
|
||||
|
||||
💡 试试发送:电影、音乐、软件、游戏
|
||||
"""
|
||||
await welcome_channel.send(welcome_msg)
|
||||
|
||||
|
||||
# ========== 命令处理 ==========
|
||||
@bot.command(name='help')
|
||||
async def cmd_help(ctx):
|
||||
"""帮助命令"""
|
||||
help_text = """
|
||||
📋 **Discord资源搜索机器人帮助**
|
||||
|
||||
**🔍 资源搜索:**
|
||||
• 直接发送关键词 - 自动搜索资源库
|
||||
• `!search 关键词` - 搜索资源
|
||||
• `!stats` - 查看资源库统计
|
||||
|
||||
**⚙️ 群管理:**
|
||||
• `!ping` - 测试机器人状态
|
||||
• `!serverinfo` - 查看服务器信息
|
||||
• `!welcome on/off` - 开启/关闭欢迎消息
|
||||
|
||||
**💡 使用示例:**
|
||||
• 发送 `电影` - 搜索电影相关资源
|
||||
• 发送 `无损音乐` - 搜索无损音乐
|
||||
• 发送 `Adobe` - 搜索Adobe软件
|
||||
|
||||
**📊 数据说明:**
|
||||
本机器人使用独立数据库,资源持续更新中...
|
||||
"""
|
||||
await ctx.send(help_text)
|
||||
|
||||
|
||||
@bot.command(name='search')
|
||||
async def cmd_search(ctx, *, keyword: str = None):
|
||||
"""搜索资源"""
|
||||
if not keyword:
|
||||
await ctx.send("❌ 请输入搜索关键词\n示例:`!search 电影`")
|
||||
return
|
||||
|
||||
await do_search(ctx, keyword)
|
||||
|
||||
|
||||
@bot.command(name='stats')
|
||||
async def cmd_stats(ctx):
|
||||
"""查看资源库统计"""
|
||||
stats = get_stats()
|
||||
|
||||
total = stats['total']
|
||||
with_link = stats['with_link']
|
||||
search_count = stats['search_count']
|
||||
link_percent = (with_link / total * 100) if total > 0 else 0
|
||||
|
||||
stats_text = f"""
|
||||
📊 **资源库统计**
|
||||
|
||||
• 📦 总资源数:**{total}** 条
|
||||
• 🔗 带跳转链接:**{with_link}** 条
|
||||
• 📈 链接占比:**{link_percent:.1f}%**
|
||||
• 🔍 总搜索次数:**{search_count}** 次
|
||||
|
||||
💡 发送关键词即可搜索资源
|
||||
"""
|
||||
await ctx.send(stats_text)
|
||||
|
||||
|
||||
@bot.command(name='ping')
|
||||
async def cmd_ping(ctx):
|
||||
"""测试机器人状态"""
|
||||
latency = bot.latency * 1000
|
||||
await ctx.send(f"🏓 Pong! 延迟: {latency:.0f}ms")
|
||||
|
||||
|
||||
@bot.command(name='serverinfo')
|
||||
async def cmd_serverinfo(ctx):
|
||||
"""查看服务器信息"""
|
||||
guild = ctx.guild
|
||||
info = f"""
|
||||
🏰 **服务器信息**
|
||||
|
||||
• 📛 名称:{guild.name}
|
||||
• 👥 成员数:{guild.member_count}
|
||||
• 📅 创建时间:{guild.created_at.strftime('%Y-%m-%d')}
|
||||
• 💬 频道数:{len(guild.text_channels)}
|
||||
• 🔊 语音频道数:{len(guild.voice_channels)}
|
||||
"""
|
||||
await ctx.send(info)
|
||||
|
||||
|
||||
@bot.command(name='welcome')
|
||||
async def cmd_welcome(ctx, action: str = None):
|
||||
"""开启/关闭欢迎消息"""
|
||||
if not action or action.lower() not in ['on', 'off']:
|
||||
await ctx.send("❌ 用法:`!welcome on` 或 `!welcome off`")
|
||||
return
|
||||
|
||||
enabled = 1 if action.lower() == 'on' else 0
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("""
|
||||
INSERT OR REPLACE INTO group_config (guild_id, guild_name, welcome_enabled)
|
||||
VALUES (?, ?, ?)
|
||||
""", (ctx.guild.id, ctx.guild.name, enabled))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
status = "✅ 已开启" if enabled else "❌ 已关闭"
|
||||
await ctx.send(f"{status} 欢迎消息")
|
||||
|
||||
|
||||
# ========== 核心搜索功能 ==========
|
||||
async def do_search(ctx, keyword, page=0):
|
||||
"""执行搜索并发送结果"""
|
||||
# 显示"正在搜索"
|
||||
search_msg = await ctx.send(f"🔍 正在搜索「{keyword}」...")
|
||||
|
||||
try:
|
||||
# 搜索资源
|
||||
results, total = search_resources(keyword, limit=PAGE_SIZE, offset=page * PAGE_SIZE)
|
||||
|
||||
# 记录搜索日志
|
||||
log_search(ctx.author.id, keyword, total)
|
||||
|
||||
# 格式化结果
|
||||
reply = format_results(results, keyword, total, page=page)
|
||||
|
||||
# 编辑消息
|
||||
await search_msg.edit(content=reply)
|
||||
|
||||
# 分页反应
|
||||
if total > PAGE_SIZE:
|
||||
await search_msg.add_reaction("⬅️")
|
||||
await search_msg.add_reaction("➡️")
|
||||
|
||||
except Exception as e:
|
||||
await search_msg.edit(content=f"❌ 搜索失败:{str(e)}")
|
||||
|
||||
|
||||
# ========== 全局消息监听 ==========
|
||||
@bot.event
|
||||
async def on_message(message):
|
||||
"""处理所有消息 - 全局资源搜索"""
|
||||
# 忽略机器人自己的消息
|
||||
if message.author == bot.user:
|
||||
return
|
||||
|
||||
# 处理命令
|
||||
await bot.process_commands(message)
|
||||
|
||||
# 如果是命令,不触发全局搜索
|
||||
if message.content.startswith('!'):
|
||||
return
|
||||
|
||||
# 忽略太短的消息
|
||||
if len(message.content.strip()) < 2:
|
||||
return
|
||||
|
||||
# 忽略包含URL的消息
|
||||
if 'http://' in message.content or 'https://' in message.content:
|
||||
return
|
||||
|
||||
# 只在服务器频道触发全局搜索
|
||||
if message.guild is None:
|
||||
return
|
||||
|
||||
# 检查是否启用搜索
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT search_enabled FROM group_config WHERE guild_id = ?", (message.guild.id,))
|
||||
result = c.fetchone()
|
||||
conn.close()
|
||||
|
||||
if result and result[0] == 0:
|
||||
return
|
||||
|
||||
# 全局资源搜索
|
||||
keyword = message.content.strip()
|
||||
await do_search(message.channel, keyword)
|
||||
|
||||
|
||||
# ========== 主函数 ==========
|
||||
def main():
|
||||
"""主函数"""
|
||||
if not DISCORD_TOKEN:
|
||||
print("❌ 错误:未配置DISCORD_TOKEN")
|
||||
print("请在.env文件中设置DISCORD_TOKEN")
|
||||
print("获取地址:https://discord.com/developers/applications")
|
||||
return
|
||||
|
||||
print("🚀 正在启动Discord机器人...")
|
||||
bot.run(DISCORD_TOKEN)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
discord.py>=2.3.0
|
||||
python-dotenv>=1.0.0
|
||||
@@ -0,0 +1,46 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo ========================================
|
||||
echo Discord资源搜索机器人 - 启动脚本
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
echo [1/3] 检查Python环境...
|
||||
python --version
|
||||
if errorlevel 1 (
|
||||
echo ❌ 未找到Python,请先安装Python 3.8+
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [2/3] 检查依赖...
|
||||
pip show discord.py >nul 2>&1
|
||||
if errorlevel 1 (
|
||||
echo 正在安装依赖...
|
||||
pip install -r requirements.txt
|
||||
) else (
|
||||
echo ✅ 依赖已安装
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [3/3] 检查配置...
|
||||
if not exist .env (
|
||||
echo ❌ 未找到.env配置文件
|
||||
echo 请复制 .env.example 为 .env 并填入DISCORD_TOKEN
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ 配置文件存在
|
||||
|
||||
echo.
|
||||
echo ========================================
|
||||
echo 正在启动Discord机器人...
|
||||
echo ========================================
|
||||
echo.
|
||||
|
||||
python bot.py
|
||||
|
||||
pause
|
||||
Reference in New Issue
Block a user