feature:1.点歌功能,2.签到功能
This commit is contained in:
@@ -47,37 +47,6 @@ class News(object):
|
|||||||
|
|
||||||
return f"{fmt_time} {self.week[weekday_news]}\n{fmt_news}"
|
return f"{fmt_time} {self.week[weekday_news]}\n{fmt_news}"
|
||||||
|
|
||||||
|
|
||||||
def get_36kr_news(self):
|
|
||||||
url = "https://orz.ai/dailynews/?platform=36kr"
|
|
||||||
# 获取当前日期和英文星期名
|
|
||||||
now = datetime.now()
|
|
||||||
current_date = now.strftime("%Y年%m月%d日")
|
|
||||||
english_weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
||||||
chinese_weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
|
|
||||||
|
|
||||||
# 将英文星期名映射为中文
|
|
||||||
current_weekday_index = now.weekday() # 获取当前是星期几(0代表星期一,6代表星期日)
|
|
||||||
current_weekday_chinese = chinese_weekdays[current_weekday_index]
|
|
||||||
|
|
||||||
# 初始化一个空字符串来存储结果
|
|
||||||
output = f"当前日期:{current_date} {current_weekday_chinese}\n\n"
|
|
||||||
|
|
||||||
response = requests.get(url)
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
post = response.json()
|
|
||||||
str = post['data']
|
|
||||||
# 遍历列表,并格式化每个字典的title, url,然后添加到output字符串中
|
|
||||||
for index, article in enumerate(str, start=1):
|
|
||||||
title = article['title']
|
|
||||||
url = article['url']
|
|
||||||
# 使用f-string格式化字符串,并添加到output中
|
|
||||||
output += f"{index}. 标题: {title}\n URL: {url}\n"
|
|
||||||
|
|
||||||
# 输出最终的字符串(这里只是为了展示,实际上你可以根据需要处理这个字符串)
|
|
||||||
return output
|
|
||||||
|
|
||||||
def get_baidu_news(self):
|
def get_baidu_news(self):
|
||||||
url = "https://top.baidu.com/api/board?platform=wise&tab=realtime"
|
url = "https://top.baidu.com/api/board?platform=wise&tab=realtime"
|
||||||
# 获取当前日期和英文星期名
|
# 获取当前日期和英文星期名
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ class ReportReminder:
|
|||||||
today = datetime.datetime.now().date()
|
today = datetime.datetime.now().date()
|
||||||
# 如果是非工作日
|
# 如果是非工作日
|
||||||
if not is_workday(today):
|
if not is_workday(today):
|
||||||
robot.sendTextMsg("休息日快乐", receiver)
|
robot.send_text_msg("休息日快乐", receiver)
|
||||||
# 如果是工作日
|
# 如果是工作日
|
||||||
if is_workday(today):
|
if is_workday(today):
|
||||||
robot.sendTextMsg("该发日报啦", receiver)
|
robot.send_text_msg("该发日报啦", receiver)
|
||||||
# 如果是本周最后一个工作日
|
# 如果是本周最后一个工作日
|
||||||
if ReportReminder.last_work_day_of_week(today) == today:
|
if ReportReminder.last_work_day_of_week(today) == today:
|
||||||
robot.sendTextMsg("该发周报啦", receiver)
|
robot.send_text_msg("该发周报啦", receiver)
|
||||||
# 如果本日是本月最后一整周的最后一个工作日:
|
# 如果本日是本月最后一整周的最后一个工作日:
|
||||||
if ReportReminder.last_work_friday_of_month(today) == today:
|
if ReportReminder.last_work_friday_of_month(today) == today:
|
||||||
robot.sendTextMsg("该发月报啦", receiver)
|
robot.send_text_msg("该发月报啦", receiver)
|
||||||
|
|
||||||
# 计算本月最后一个周的最后一个工作日
|
# 计算本月最后一个周的最后一个工作日
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
21
config.yaml
21
config.yaml
@@ -120,3 +120,24 @@ doubao:
|
|||||||
- 问题评价:分析问题的提出角度,如(财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐)等
|
- 问题评价:分析问题的提出角度,如(财经、彩票、房产、股票、家居、教育、科技、社会、时尚、时政、体育、星座、游戏、娱乐)等
|
||||||
- 总结:经过300个字以内的优化返回,返回内容请进行一定程度的结构化,方便快速阅读' # 根据需要对角色进行设定
|
- 总结:经过300个字以内的优化返回,返回内容请进行一定程度的结构化,方便快速阅读' # 根据需要对角色进行设定
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# config.yaml
|
||||||
|
|
||||||
|
db_config:
|
||||||
|
pool_name: "wechat_boot_pool"
|
||||||
|
pool_size: 10
|
||||||
|
host: "192.168.2.32"
|
||||||
|
user: "root"
|
||||||
|
password: "lw123456"
|
||||||
|
database: "message_archive"
|
||||||
|
charset: "utf8mb4"
|
||||||
|
use_unicode: true
|
||||||
|
get_warnings: true
|
||||||
|
pool_reset_session: true
|
||||||
|
|
||||||
|
redis_config:
|
||||||
|
host: "192.168.2.32"
|
||||||
|
port: 6379
|
||||||
|
db: 0
|
||||||
|
decode_responses: true
|
||||||
@@ -40,3 +40,7 @@ class Config(object):
|
|||||||
self.CLAUDE = yconfig.get("claude", {})
|
self.CLAUDE = yconfig.get("claude", {})
|
||||||
self.DEEPSEEK = yconfig.get("deepseek", {})
|
self.DEEPSEEK = yconfig.get("deepseek", {})
|
||||||
self.DOUBAO = yconfig.get("doubao", {})
|
self.DOUBAO = yconfig.get("doubao", {})
|
||||||
|
|
||||||
|
# DB config
|
||||||
|
self.mariadb = yconfig.get("db_config", {})
|
||||||
|
self.redis = yconfig.get("redis_config", {})
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ import xml.etree.ElementTree as ET
|
|||||||
from wcferry import Wcf
|
from wcferry import Wcf
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GroupMemberChange:
|
class GroupMemberChange:
|
||||||
def __init__(self, wcf: Wcf):
|
def __init__(self, wcf: Wcf, redis_pool: redis.ConnectionPool):
|
||||||
self.wcf = wcf # 假设 wcf 对象在此类中初始化
|
self.wcf = wcf # 假设 wcf 对象在此类中初始化
|
||||||
self.r = redis.Redis(host='192.168.2.32', port=6379, db=0, decode_responses=True)
|
self.redis_pool = redis_pool
|
||||||
# 初始化本地缓存字典,使用 group_id 作为键
|
# 初始化本地缓存字典,使用 group_id 作为键
|
||||||
self.local_membercounts = {}
|
self.local_membercounts = {}
|
||||||
self.local_members = {}
|
self.local_members = {}
|
||||||
|
|
||||||
|
def _get_redis_connection(self):
|
||||||
|
"""从连接池获取 Redis 连接"""
|
||||||
|
return redis.Redis(connection_pool=self.redis_pool)
|
||||||
|
|
||||||
def get_current_members(self, group_id):
|
def get_current_members(self, group_id):
|
||||||
""" 获取当前群成员信息 """
|
""" 获取当前群成员信息 """
|
||||||
print(f"Fetching current members for group_id: {group_id}")
|
print(f"Fetching current members for group_id: {group_id}")
|
||||||
@@ -27,8 +30,8 @@ class GroupMemberChange:
|
|||||||
|
|
||||||
# 读取 Redis 中的数据
|
# 读取 Redis 中的数据
|
||||||
print(f"Fetching previous data from Redis for group_id: {group_id}")
|
print(f"Fetching previous data from Redis for group_id: {group_id}")
|
||||||
membercount_previous = self.r.get(membercount_key)
|
membercount_previous = self._get_redis_connection().get(membercount_key)
|
||||||
members_previous = self.r.hgetall(members_key) # 获取上次的成员信息
|
members_previous = self._get_redis_connection().hgetall(members_key) # 获取上次的成员信息
|
||||||
print(f"Previous membercount: {membercount_previous}, Previous members: {members_previous}")
|
print(f"Previous membercount: {membercount_previous}, Previous members: {members_previous}")
|
||||||
return membercount_previous, members_previous
|
return membercount_previous, members_previous
|
||||||
|
|
||||||
@@ -48,9 +51,10 @@ class GroupMemberChange:
|
|||||||
if membercount_previous is None or not members_previous:
|
if membercount_previous is None or not members_previous:
|
||||||
print("First time processing, saving current data to Redis")
|
print("First time processing, saving current data to Redis")
|
||||||
members_current = self.get_current_members(group_id)
|
members_current = self.get_current_members(group_id)
|
||||||
self.r.set(f"group:group_member_count:{group_id}", membercount_current)
|
self._get_redis_connection().set(f"group:group_member_count:{group_id}", membercount_current)
|
||||||
self.r.delete(f"group:group_members:{group_id}")
|
self._get_redis_connection().delete(f"group:group_members:{group_id}")
|
||||||
self.r.hset(f"group:group_members:{group_id}", mapping=members_current) # 存储当前成员信息
|
self._get_redis_connection().hset(f"group:group_members:{group_id}",
|
||||||
|
mapping=members_current) # 存储当前成员信息
|
||||||
|
|
||||||
# 更新本地缓存
|
# 更新本地缓存
|
||||||
self.local_membercounts[group_id] = membercount_current
|
self.local_membercounts[group_id] = membercount_current
|
||||||
@@ -99,11 +103,11 @@ class GroupMemberChange:
|
|||||||
|
|
||||||
# 更新 Redis 数据
|
# 更新 Redis 数据
|
||||||
print(f"Updating Redis with current membercount and members")
|
print(f"Updating Redis with current membercount and members")
|
||||||
self.r.set(f"group:group_member_count:{group_id}", membercount_current)
|
self._get_redis_connection.set(f"group:group_member_count:{group_id}", membercount_current)
|
||||||
|
|
||||||
self.r.delete(f"group:group_members:{group_id}")
|
self._get_redis_connection.delete(f"group:group_members:{group_id}")
|
||||||
# 更新 Redis 中的成员信息,确保在成员变化时也更新
|
# 更新 Redis 中的成员信息,确保在成员变化时也更新
|
||||||
self.r.hset(f"group:group_members:{group_id}", mapping=members_current)
|
self._get_redis_connection.hset(f"group:group_members:{group_id}", mapping=members_current)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
result.append("$NO_CHANGE$")
|
result.append("$NO_CHANGE$")
|
||||||
|
|||||||
14
main.py
14
main.py
@@ -25,25 +25,25 @@ def main(chat_type: int):
|
|||||||
robot.LOG.info(f"WeChatRobot【{__version__}】成功启动···")
|
robot.LOG.info(f"WeChatRobot【{__version__}】成功启动···")
|
||||||
|
|
||||||
# 机器人启动发送测试消息
|
# 机器人启动发送测试消息
|
||||||
robot.sendTextMsg("机器人启动成功!", "filehelper")
|
robot.send_text_msg("机器人启动成功!", "filehelper")
|
||||||
|
|
||||||
# 接收消息
|
# 接收消息
|
||||||
# robot.enableRecvMsg() # 可能会丢消息?
|
# robot.enableRecvMsg() # 可能会丢消息?
|
||||||
robot.enableReceivingMsg() # 加队列
|
robot.enableReceivingMsg() # 加队列
|
||||||
|
|
||||||
# 每天 8:30 发送新闻
|
# 每天 8:30 发送新闻
|
||||||
robot.onEveryTime("08:30", robot.newsBaiduReportAuto)
|
robot.onEveryTime("08:30", robot.news_baidu_report_auto)
|
||||||
|
|
||||||
# epic
|
# epic
|
||||||
robot.onEveryTime("10:30", robot.sendEpicFreeGames)
|
robot.onEveryTime("10:30", robot.send_epic_free_games)
|
||||||
|
|
||||||
# message report 1:数据自动从redis 转到sqllite
|
# message report 1:数据自动从redis 转到sqllite
|
||||||
robot.onEveryTime("00:30", robot.messageCountToDB)
|
robot.onEveryTime("00:30", robot.message_count_to_db)
|
||||||
# 从db中提取并发送给相关群
|
# 从db中提取并发送给相关群
|
||||||
robot.onEveryTime("09:30", robot.generateAndSendRanking)
|
robot.onEveryTime("09:30", robot.generate_and_send_ranking)
|
||||||
|
|
||||||
# sehuatang
|
# sehuatang
|
||||||
robot.onEveryTime("15:00", robot.generateSehuatangPdf)
|
robot.onEveryTime("15:00", robot.generate_sehuatang_pdf)
|
||||||
|
|
||||||
# 游戏的定时任务每小时执行
|
# 游戏的定时任务每小时执行
|
||||||
robot.onEveryTime("18:00", robot.game_auto_tasks)
|
robot.onEveryTime("18:00", robot.game_auto_tasks)
|
||||||
@@ -55,7 +55,7 @@ def main(chat_type: int):
|
|||||||
robot.onEveryTime("17:30", robot.xiu_ren_pdf_send)
|
robot.onEveryTime("17:30", robot.xiu_ren_pdf_send)
|
||||||
|
|
||||||
# 让机器人一直跑
|
# 让机器人一直跑
|
||||||
robot.keepRunningAndBlockProcess()
|
robot.keep_running_and_block_process()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
7
message_sign/config.toml
Normal file
7
message_sign/config.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[SignIn]
|
||||||
|
enable = true
|
||||||
|
command = ["签到", "每日签到", "qd", "Qd", "QD"]
|
||||||
|
min-point = 3
|
||||||
|
max-point = 20
|
||||||
|
streak-cycle = 5 # 每签到?天后,额外积分奖励加1点?
|
||||||
|
max-streak-point = 10 # 额外积分奖励上限
|
||||||
233
message_sign/main.py
Normal file
233
message_sign/main.py
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import mysql.connector.pooling
|
||||||
|
import tomllib
|
||||||
|
import pytz
|
||||||
|
import redis
|
||||||
|
from typing import Optional, Tuple
|
||||||
|
|
||||||
|
from wcferry import Wcf, WxMsg
|
||||||
|
from robot_cmd.robot_command import GroupBotManager, Feature, PermissionStatus
|
||||||
|
|
||||||
|
# 创建表的SQL语句
|
||||||
|
CREATE_TABLE_SQL = """
|
||||||
|
CREATE TABLE IF NOT EXISTS t_sign_record (
|
||||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
wx_id VARCHAR(100) NOT NULL,
|
||||||
|
group_id VARCHAR(100) NOT NULL,
|
||||||
|
wx_nick_name VARCHAR(100) NOT NULL,
|
||||||
|
points INT DEFAULT 0,
|
||||||
|
sign_stat DATETIME,
|
||||||
|
signin_streak INT DEFAULT 0,
|
||||||
|
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY unique_sign (wx_id, group_id)
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class SignInSystem:
|
||||||
|
def __init__(self, wcf: Wcf, gbm: GroupBotManager, all_contacts: dict,
|
||||||
|
db_pool: mysql.connector.pooling.MySQLConnectionPool, redis_pool: redis.ConnectionPool):
|
||||||
|
# 读取配置文件
|
||||||
|
with open('message_sign/config.toml', 'rb') as f:
|
||||||
|
self.config = tomllib.load(f)['SignIn']
|
||||||
|
|
||||||
|
self.LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
if not self.config['enable']:
|
||||||
|
raise Exception("签到功能未启用")
|
||||||
|
|
||||||
|
self.wcf = wcf
|
||||||
|
self.gbm = gbm
|
||||||
|
self.all_contacts = all_contacts
|
||||||
|
self.db_pool = db_pool
|
||||||
|
self.redis_pool = redis_pool
|
||||||
|
self.command = self.config['command']
|
||||||
|
self.min_point = self.config['min-point']
|
||||||
|
self.max_point = self.config['max-point']
|
||||||
|
self.streak_cycle = self.config['streak-cycle']
|
||||||
|
self.max_streak_point = self.config['max-streak-point']
|
||||||
|
# 时区设置
|
||||||
|
self.timezone = 'Asia/Shanghai'
|
||||||
|
|
||||||
|
# 从 Redis 初始化签到数据
|
||||||
|
self.today_signin_count = self._load_signin_count_from_redis()
|
||||||
|
with self._get_redis_connection() as redis_client:
|
||||||
|
last_reset_date_str = redis_client.get('group:sign_in:last_reset_date')
|
||||||
|
if last_reset_date_str:
|
||||||
|
self.last_reset_date = datetime.datetime.strptime(last_reset_date_str, '%Y-%m-%d').date()
|
||||||
|
else:
|
||||||
|
self.last_reset_date = datetime.datetime.now(tz=pytz.timezone(self.timezone)).date()
|
||||||
|
self._save_last_reset_date_to_redis()
|
||||||
|
|
||||||
|
self.LOG.info(f"[签到] 组件初始化完成 {self.command_format}")
|
||||||
|
|
||||||
|
def _get_db_connection(self):
|
||||||
|
"""从连接池获取数据库连接"""
|
||||||
|
return self.db_pool.get_connection()
|
||||||
|
|
||||||
|
def _get_redis_connection(self):
|
||||||
|
"""从连接池获取 Redis 连接"""
|
||||||
|
return redis.Redis(connection_pool=self.redis_pool)
|
||||||
|
|
||||||
|
def _load_signin_count_from_redis(self) -> dict:
|
||||||
|
"""从 Redis 加载签到人数数据"""
|
||||||
|
signin_count = {}
|
||||||
|
with self._get_redis_connection() as redis_client:
|
||||||
|
keys = redis_client.keys('group:sign_in:*')
|
||||||
|
for key in keys:
|
||||||
|
if key == 'group:sign_in:last_reset_date':
|
||||||
|
continue
|
||||||
|
group_id = key.replace('group:sign_in:', '')
|
||||||
|
count = redis_client.get(key)
|
||||||
|
if count is not None:
|
||||||
|
signin_count[group_id] = int(count)
|
||||||
|
return signin_count
|
||||||
|
|
||||||
|
def _save_signin_count_to_redis(self, group_id: str, count: int):
|
||||||
|
"""保存签到人数到 Redis"""
|
||||||
|
with self._get_redis_connection() as redis_client:
|
||||||
|
redis_client.set(f'group:sign_in:{group_id}', count)
|
||||||
|
|
||||||
|
def _save_last_reset_date_to_redis(self):
|
||||||
|
"""保存最后重置日期到 Redis"""
|
||||||
|
with self._get_redis_connection() as redis_client:
|
||||||
|
redis_client.set('group:sign_in:last_reset_date', self.last_reset_date.strftime('%Y-%m-%d'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def command_format(self):
|
||||||
|
return ','.join(self.command)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enable(self):
|
||||||
|
return self.config['enable']
|
||||||
|
|
||||||
|
def initialize_table(self):
|
||||||
|
"""初始化数据库表"""
|
||||||
|
with self._get_db_connection() as conn:
|
||||||
|
with conn.cursor(dictionary=True) as cursor: # 使用 dictionary=True 返回字典格式
|
||||||
|
cursor.execute(CREATE_TABLE_SQL)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
def reset_today_count_if_needed(self):
|
||||||
|
"""检查并重置每日签到计数"""
|
||||||
|
current_date = datetime.datetime.now(tz=pytz.timezone(self.timezone)).date()
|
||||||
|
if current_date != self.last_reset_date:
|
||||||
|
self.today_signin_count.clear()
|
||||||
|
with self._get_redis_connection() as redis_client:
|
||||||
|
keys = redis_client.keys('group:sign_in:*')
|
||||||
|
for key in keys:
|
||||||
|
if key != 'group:sign_in:last_reset_date':
|
||||||
|
redis_client.delete(key)
|
||||||
|
self.last_reset_date = current_date
|
||||||
|
self._save_last_reset_date_to_redis()
|
||||||
|
self.LOG.info(f"[签到] 已重置每日签到计数,日期更新为 {current_date}")
|
||||||
|
|
||||||
|
def get_today_signin_count(self, group_id: str) -> int:
|
||||||
|
"""获取群内今日签到人数(使用缓存)"""
|
||||||
|
self.reset_today_count_if_needed()
|
||||||
|
return self.today_signin_count.get(group_id, 0)
|
||||||
|
|
||||||
|
def get_user_record(self, wx_id: str, group_id: str) -> Optional[dict]:
|
||||||
|
"""获取用户签到记录"""
|
||||||
|
with self._get_db_connection() as conn:
|
||||||
|
with conn.cursor(dictionary=True) as cursor:
|
||||||
|
query = """
|
||||||
|
SELECT wx_id, group_id, wx_nick_name, points, sign_stat, signin_streak
|
||||||
|
FROM t_sign_record
|
||||||
|
WHERE wx_id = %s AND group_id = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(query, (wx_id, group_id))
|
||||||
|
return cursor.fetchone()
|
||||||
|
|
||||||
|
def calculate_points(self, streak: int) -> int:
|
||||||
|
"""根据连续签到天数计算积分"""
|
||||||
|
base_points = self.min_point
|
||||||
|
extra_points = min(streak // self.streak_cycle, self.max_streak_point)
|
||||||
|
total_points = base_points + extra_points
|
||||||
|
return min(total_points, self.max_point)
|
||||||
|
|
||||||
|
def member_sign_in(self, message: WxMsg):
|
||||||
|
"""会员签到功能"""
|
||||||
|
if not self.enable:
|
||||||
|
return
|
||||||
|
|
||||||
|
content = str(message.content).strip()
|
||||||
|
command = content.split(" ")
|
||||||
|
if not len(command) or command[0] not in self.command:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.gbm.get_group_permission(message.roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
|
||||||
|
return
|
||||||
|
|
||||||
|
current_time = datetime.datetime.now(tz=pytz.timezone(self.timezone))
|
||||||
|
today_start = current_time.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
yesterday = today_start - datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
user_record = self.get_user_record(message.sender, message.roomid)
|
||||||
|
wx_nick_name = self.all_contacts.get(message.sender, message.sender)
|
||||||
|
|
||||||
|
if user_record and user_record['sign_stat'] and user_record['sign_stat'] >= today_start:
|
||||||
|
self.wcf.send_text(
|
||||||
|
f"@{wx_nick_name} 您今天已经签到过了!当前积分:{user_record['points']}",
|
||||||
|
message.sender
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
streak = 0
|
||||||
|
if user_record and user_record['sign_stat']:
|
||||||
|
last_sign_date = user_record['sign_stat'].replace(hour=0, minute=0, second=0, microsecond=0)
|
||||||
|
if last_sign_date == yesterday:
|
||||||
|
streak = user_record['signin_streak'] + 1
|
||||||
|
else:
|
||||||
|
streak = 1
|
||||||
|
else:
|
||||||
|
streak = 1
|
||||||
|
|
||||||
|
today_signin_rank = self.get_today_signin_count(message.roomid) + 1
|
||||||
|
self.today_signin_count[message.roomid] = today_signin_rank
|
||||||
|
self._save_signin_count_to_redis(message.roomid, today_signin_rank)
|
||||||
|
|
||||||
|
points_to_add = self.calculate_points(streak)
|
||||||
|
|
||||||
|
with self._get_db_connection() as conn:
|
||||||
|
with conn.cursor(dictionary=True) as cursor:
|
||||||
|
if user_record:
|
||||||
|
update_sql = """
|
||||||
|
UPDATE t_sign_record
|
||||||
|
SET wx_nick_name = %s, points = points + %s,
|
||||||
|
sign_stat = %s, signin_streak = %s,
|
||||||
|
update_time = %s
|
||||||
|
WHERE wx_id = %s AND group_id = %s
|
||||||
|
"""
|
||||||
|
cursor.execute(update_sql, (
|
||||||
|
wx_nick_name, points_to_add, current_time, streak,
|
||||||
|
current_time, message.sender, message.roomid
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
insert_sql = """
|
||||||
|
INSERT INTO t_sign_record
|
||||||
|
(wx_id, group_id, wx_nick_name, points, sign_stat, signin_streak)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
cursor.execute(insert_sql, (
|
||||||
|
message.sender, message.roomid, wx_nick_name, points_to_add, current_time, streak
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
msg = (
|
||||||
|
f"@{wx_nick_name} 签到成功!\n"
|
||||||
|
f"您是今日群内第{today_signin_rank}个签到的\n"
|
||||||
|
f"连续签到{streak}天,本次获得{points_to_add}积分"
|
||||||
|
)
|
||||||
|
self.wcf.send_text(
|
||||||
|
msg,
|
||||||
|
(message.roomid if message.from_group() else message.sender),
|
||||||
|
message.sender
|
||||||
|
)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""连接池由外部管理,不需要手动关闭"""
|
||||||
|
pass
|
||||||
|
|
||||||
@@ -4,120 +4,109 @@ import redis
|
|||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from message_summary.message_summary_4o import message_summary
|
from message_summary.message_summary_4o import message_summary
|
||||||
|
|
||||||
# 配置数据库连接
|
import mysql.connector.pooling
|
||||||
db_config = {
|
|
||||||
'host': '192.168.2.32', # 替换为你的MariaDB服务器地址
|
|
||||||
'user': 'root', # 替换为你的MariaDB用户名
|
|
||||||
'password': 'lw123456', # 替换为你的MariaDB密码
|
|
||||||
'database': 'message_archive'
|
|
||||||
}
|
|
||||||
|
|
||||||
# 连接到Redis
|
|
||||||
r = redis.Redis(host='192.168.2.32', port=6379, db=0)
|
|
||||||
|
|
||||||
|
|
||||||
def archive_message(group_id, timestamp_str, sender, content, message_type, attachment_url=None):
|
class MessageStorage:
|
||||||
# 连接到数据库
|
|
||||||
connection = pymysql.connect(**db_config)
|
|
||||||
|
|
||||||
try:
|
def __init__(self, db_pool: mysql.connector.pooling.MySQLConnectionPool, redis_pool: redis.ConnectionPool):
|
||||||
with connection.cursor() as cursor:
|
self.redis_pool = redis_pool
|
||||||
# 插入消息信息
|
self.db_pool = db_pool
|
||||||
sql = """
|
# 初始化本地缓存字典,使用 group_id 作为键
|
||||||
INSERT INTO messages (group_id,timestamp, sender, content, message_type, attachment_url)
|
self.local_membercounts = {}
|
||||||
VALUES (%s, %s, %s, %s, %s, %s)
|
self.local_members = {}
|
||||||
"""
|
|
||||||
cursor.execute(sql, (group_id, timestamp_str, sender, content, message_type, attachment_url))
|
|
||||||
|
|
||||||
# 提交事务
|
def _get_redis_connection(self):
|
||||||
connection.commit()
|
"""从连接池获取 Redis 连接"""
|
||||||
print(f"Archived:{timestamp_str}:{group_id}:{sender}: {content}")
|
return redis.Redis(connection_pool=self.redis_pool)
|
||||||
|
|
||||||
except Exception as e:
|
def archive_message(self, group_id, timestamp_str, sender, content, message_type, attachment_url=None):
|
||||||
print(f"Error archiving message: {e}")
|
# 连接到数据库
|
||||||
connection.rollback()
|
connection = self.db_pool.get_connection()
|
||||||
|
|
||||||
finally:
|
try:
|
||||||
# 关闭连接
|
with connection.cursor() as cursor:
|
||||||
connection.close()
|
# 插入消息信息
|
||||||
|
sql = """
|
||||||
|
INSERT INTO messages (group_id,timestamp, sender, content, message_type, attachment_url)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
cursor.execute(sql, (group_id, timestamp_str, sender, content, message_type, attachment_url))
|
||||||
|
|
||||||
|
# 提交事务
|
||||||
|
connection.commit()
|
||||||
|
print(f"Archived:{timestamp_str}:{group_id}:{sender}: {content}")
|
||||||
|
|
||||||
def get_messages(group_id, all_contacts: dict):
|
except Exception as e:
|
||||||
# 连接到数据库
|
print(f"Error archiving message: {e}")
|
||||||
with pymysql.connect(**db_config) as connection:
|
connection.rollback()
|
||||||
# 获取 redis 中的上次总结时间,本次从上次开始算,若没有,则从 8 小时之前开始计算
|
|
||||||
key = f"{group_id}:summary_time"
|
|
||||||
last_summary_time = r.get(key)
|
|
||||||
|
|
||||||
# 如果 Redis 返回值为字节类型,转换为字符串
|
finally:
|
||||||
if last_summary_time:
|
# 关闭连接
|
||||||
last_summary_time = last_summary_time.decode('utf-8')
|
connection.close()
|
||||||
|
|
||||||
current_time = datetime.now()
|
def get_messages(self, group_id, all_contacts: dict):
|
||||||
current_date = current_time.strftime('%Y-%m-%d %H:%M:%S')
|
# 连接到数据库
|
||||||
|
with self.db_pool.get_connection() as connection:
|
||||||
|
# 获取 redis 中的上次总结时间,本次从上次开始算,若没有,则从 8 小时之前开始计算
|
||||||
|
key = f"{group_id}:summary_time"
|
||||||
|
last_summary_time = self._get_redis_connection().get(key)
|
||||||
|
|
||||||
if not last_summary_time:
|
# 如果 Redis 返回值为字节类型,转换为字符串
|
||||||
# 获取当前时间并计算 8 小时前的时间
|
if last_summary_time:
|
||||||
eight_hours_ago = current_time - timedelta(hours=8)
|
last_summary_time = last_summary_time.decode('utf-8')
|
||||||
last_summary_time = eight_hours_ago.strftime('%Y-%m-%d %H:%M:%S')
|
|
||||||
else:
|
|
||||||
# 检查 redis 中的时间与当前时间差是否小于 3 小时
|
|
||||||
last_summary_time_obj = datetime.strptime(last_summary_time, '%Y-%m-%d %H:%M:%S')
|
|
||||||
time_diff = current_time - last_summary_time_obj
|
|
||||||
|
|
||||||
if time_diff < timedelta(hours=3):
|
current_time = datetime.now()
|
||||||
# 如果小于 3 小时,取当天的内容
|
current_date = current_time.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
last_summary_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0).strftime(
|
|
||||||
'%Y-%m-%d %H:%M:%S')
|
|
||||||
elif time_diff > timedelta(days=1):
|
|
||||||
# 如果超过 24 小时,将时间设置为当天 0 点
|
|
||||||
last_summary_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0).strftime(
|
|
||||||
'%Y-%m-%d %H:%M:%S')
|
|
||||||
|
|
||||||
# 更新 Redis 存储的当前时间
|
if not last_summary_time:
|
||||||
# r.set(key, current_date)
|
# 获取当前时间并计算 8 小时前的时间
|
||||||
|
eight_hours_ago = current_time - timedelta(hours=8)
|
||||||
|
last_summary_time = eight_hours_ago.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
else:
|
||||||
|
# 检查 redis 中的时间与当前时间差是否小于 3 小时
|
||||||
|
last_summary_time_obj = datetime.strptime(last_summary_time, '%Y-%m-%d %H:%M:%S')
|
||||||
|
time_diff = current_time - last_summary_time_obj
|
||||||
|
|
||||||
with connection.cursor() as cursor:
|
if time_diff < timedelta(hours=3):
|
||||||
# 执行查询,获取最近 8 小时的消息
|
# 如果小于 3 小时,取当天的内容
|
||||||
query = """
|
last_summary_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0).strftime(
|
||||||
SELECT timestamp, sender, content,message_type
|
'%Y-%m-%d %H:%M:%S')
|
||||||
FROM messages
|
elif time_diff > timedelta(days=1):
|
||||||
WHERE timestamp >= %s AND message_type in(1,49) AND group_id = %s
|
# 如果超过 24 小时,将时间设置为当天 0 点
|
||||||
"""
|
last_summary_time = current_time.replace(hour=0, minute=0, second=0, microsecond=0).strftime(
|
||||||
cursor.execute(query, (last_summary_time, group_id))
|
'%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
# 构建最终的结果字符串
|
# 更新 Redis 存储的当前时间
|
||||||
# message_type 需要加入49类型,因为49是引用之后的发言。但是49是xml ,需要将content进行xml解析
|
# r.set(key, current_date)
|
||||||
|
|
||||||
result = []
|
with connection.cursor() as cursor:
|
||||||
for row in cursor.fetchall():
|
# 执行查询,获取最近 8 小时的消息
|
||||||
timestamp, sender, content, message_type = row
|
query = """
|
||||||
try:
|
SELECT timestamp, sender, content,message_type
|
||||||
if message_type == "49":
|
FROM messages
|
||||||
# 解析 XML 字符串
|
WHERE timestamp >= %s AND message_type in(1,49) AND group_id = %s
|
||||||
root = ET.fromstring(content)
|
"""
|
||||||
# 提取 title 内容
|
cursor.execute(query, (last_summary_time, group_id))
|
||||||
content = root.find('.//title').text
|
|
||||||
|
|
||||||
except Exception as e:
|
# 构建最终的结果字符串
|
||||||
print(f"message_type 49 error: {e}")
|
# message_type 需要加入49类型,因为49是引用之后的发言。但是49是xml ,需要将content进行xml解析
|
||||||
sender_name = all_contacts.get(sender, sender) # 获取发送者的名字,若找不到则使用原 ID
|
|
||||||
result.append(f"{timestamp},{sender_name},{content}")
|
|
||||||
|
|
||||||
result_str = "\n".join(result) # 将结果拼接为最终字符串
|
result = []
|
||||||
print(result_str)
|
for row in cursor.fetchall():
|
||||||
return result_str
|
timestamp, sender, content, message_type = row
|
||||||
|
try:
|
||||||
|
if message_type == "49":
|
||||||
|
# 解析 XML 字符串
|
||||||
|
root = ET.fromstring(content)
|
||||||
|
# 提取 title 内容
|
||||||
|
content = root.find('.//title').text
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"message_type 49 error: {e}")
|
||||||
|
sender_name = all_contacts.get(sender, sender) # 获取发送者的名字,若找不到则使用原 ID
|
||||||
|
result.append(f"{timestamp},{sender_name},{content}")
|
||||||
|
|
||||||
# 示例用法
|
result_str = "\n".join(result) # 将结果拼接为最终字符串
|
||||||
if __name__ == "__main__":
|
print(result_str)
|
||||||
# group_id = 'XXX@123123'
|
return result_str
|
||||||
# timestamp_str = "2025-02-06 11:15:28"
|
|
||||||
# sender = "XXX"
|
|
||||||
# content = "This is a test message with a string timestamp."
|
|
||||||
# message_type = "text"
|
|
||||||
# attachment_url = "http://example.com/attachment.pdf" # 可以为None如果没有附件
|
|
||||||
#
|
|
||||||
# archive_message(group_id, timestamp_str, sender, content, message_type, attachment_url)
|
|
||||||
# get_messages("45317011307@chatroom", {})
|
|
||||||
message_summary(get_messages("45317011307@chatroom", {}))
|
|
||||||
|
|||||||
63
music/bot_music.py
Normal file
63
music/bot_music.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import logging
|
||||||
|
import tomllib
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from wcferry import WxMsg, Wcf
|
||||||
|
|
||||||
|
from robot_cmd.robot_command import Feature, PermissionStatus, GroupBotManager
|
||||||
|
|
||||||
|
|
||||||
|
class BotMusic:
|
||||||
|
def __init__(self, wcf: Wcf, gbm: GroupBotManager):
|
||||||
|
self.LOG = logging.getLogger(__name__)
|
||||||
|
self.wcf = wcf # 假设 wcf 对象在此类中初始化
|
||||||
|
self.gbm = gbm # 权限功能
|
||||||
|
with open("music/config.toml", "rb") as f:
|
||||||
|
plugin_config = tomllib.load(f)
|
||||||
|
|
||||||
|
config = plugin_config["Music"]
|
||||||
|
|
||||||
|
self.enable = config["enable"]
|
||||||
|
self.command = config["command"]
|
||||||
|
self.command_format = config["command-format"]
|
||||||
|
self.LOG.info(f"[点歌台] 组件初始化完成,指令: {self.command}")
|
||||||
|
|
||||||
|
async def get_music(self, message: WxMsg):
|
||||||
|
if not self.enable:
|
||||||
|
return
|
||||||
|
|
||||||
|
content = str(message.content).strip()
|
||||||
|
command = content.split(" ")
|
||||||
|
|
||||||
|
if command[0] not in self.command:
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(command) == 1:
|
||||||
|
self.wcf.send_text(f"-----Bot-----\n❌命令格式错误!{self.command_format}",
|
||||||
|
(message.roomid if message.from_group() else message.sender), message.sender)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 如果触发了指令,但是没有权限,则返回权限不足
|
||||||
|
if self.gbm.get_group_permission(message.roomid, Feature.TASK_GAME) == PermissionStatus.DISABLED:
|
||||||
|
return
|
||||||
|
|
||||||
|
song_name = content[len(command[0]):].strip()
|
||||||
|
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(
|
||||||
|
f"https://www.hhlqilongzhu.cn/api/dg_wyymusic.php?gm={song_name}&n=1&br=2&type=json") as resp:
|
||||||
|
data = await resp.json()
|
||||||
|
|
||||||
|
if data["code"] != 200:
|
||||||
|
self.wcf.send_text(f"-----Bot-----\n❌点歌失败!\n{data}",
|
||||||
|
(message.roomid if message.from_group() else message.sender), message.sender)
|
||||||
|
return
|
||||||
|
title = data["title"]
|
||||||
|
singer = data["singer"]
|
||||||
|
url = data["link"]
|
||||||
|
music_url = data["music_url"].split("?")[0]
|
||||||
|
cover_url = data["cover"]
|
||||||
|
lyric = data["lrc"]
|
||||||
|
|
||||||
|
xml = f"""<appmsg appid="wx79f2c4418704b4f8" sdkver="0"><title>{title}</title><des>{singer}</des><action>view</action><type>3</type><showtype>0</showtype><content/><url>{url}</url><dataurl>{music_url}</dataurl><lowurl>{url}</lowurl><lowdataurl>{music_url}</lowdataurl><recorditem/><thumburl>{cover_url}</thumburl><messageaction/><laninfo/><extinfo/><sourceusername/><sourcedisplayname/><songlyric>{lyric}</songlyric><commenturl/><appattach><totallen>0</totallen><attachid/><emoticonmd5/><fileext/><aeskey/></appattach><webviewshared><publisherId/><publisherReqId>0</publisherReqId></webviewshared><weappinfo><pagepath/><username/><appid/><appservicetype>0</appservicetype></weappinfo><websearch/><songalbumurl>{cover_url}</songalbumurl></appmsg><fromusername>{bot.wxid}</fromusername><scene>0</scene><appinfo><version>1</version><appname/></appinfo><commenturl/>"""
|
||||||
|
self.wcf.send_xml(message.sender, xml, 3)
|
||||||
8
music/config.toml
Normal file
8
music/config.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[Music]
|
||||||
|
enable = true
|
||||||
|
command = ["点歌", "音乐", "音乐点播", "点播音乐", "音乐点歌"]
|
||||||
|
command-format = """
|
||||||
|
-----Bot-----
|
||||||
|
🎵点歌指令:
|
||||||
|
点歌 歌曲名
|
||||||
|
"""
|
||||||
@@ -27,3 +27,7 @@ selenium~=4.28.1
|
|||||||
webdriver-manager~=4.0.2
|
webdriver-manager~=4.0.2
|
||||||
reportlab~=4.3.0
|
reportlab~=4.3.0
|
||||||
PyPDF2~=3.0.1
|
PyPDF2~=3.0.1
|
||||||
|
Flask~=3.1.0
|
||||||
|
aiohttp~=3.11.12
|
||||||
|
mysql-connector-python~=9.2.0
|
||||||
|
pytz~=2025.1
|
||||||
119
robot.py
119
robot.py
@@ -9,6 +9,8 @@ from threading import Thread
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
import redis
|
||||||
|
|
||||||
from base.func_doubao import Doubao
|
from base.func_doubao import Doubao
|
||||||
from base.func_epic import is_friday, get_free
|
from base.func_epic import is_friday, get_free
|
||||||
from base.func_zhipu import ZhiPu
|
from base.func_zhipu import ZhiPu
|
||||||
@@ -29,16 +31,19 @@ from game_task.game_task_encyclopedia import game_process_message, setup_schedul
|
|||||||
run_random_task_assignment
|
run_random_task_assignment
|
||||||
from group_auto.group_auto_invite import get_first_group_id, process_command
|
from group_auto.group_auto_invite import get_first_group_id, process_command
|
||||||
from group_auto.group_member_change import GroupMemberChange
|
from group_auto.group_member_change import GroupMemberChange
|
||||||
|
from message_sign.main import SignInSystem
|
||||||
|
from message_storage.message_to_db import MessageStorage
|
||||||
|
from music.bot_music import BotMusic
|
||||||
from robot_cmd.robot_command import GroupBotManager
|
from robot_cmd.robot_command import GroupBotManager
|
||||||
from job_mgmt import Job
|
from job_mgmt import Job
|
||||||
from robot_cmd.robot_command import Feature
|
from robot_cmd.robot_command import Feature
|
||||||
from robot_cmd.robot_command import PermissionStatus
|
from robot_cmd.robot_command import PermissionStatus
|
||||||
|
import mysql.connector.pooling
|
||||||
|
|
||||||
__version__ = "39.2.4.0"
|
__version__ = "39.2.4.0"
|
||||||
|
|
||||||
from message_report.process_message import process_message
|
from message_report.process_message import process_message
|
||||||
from message_report.write_db import write_to_db, generate_and_send_ranking
|
from message_report.write_db import write_to_db, generate_and_send_ranking
|
||||||
from message_storage.message_to_db import archive_message, get_messages
|
|
||||||
from message_summary.message_summary_4o import message_summary
|
from message_summary.message_summary_4o import message_summary
|
||||||
from sehuatang.shehuatang import pdf_file_path
|
from sehuatang.shehuatang import pdf_file_path
|
||||||
from xiuren.meitu_dl import meitu_dowload_pic, meitu_dowload_pub_pic, meitu_dowload_heisi_pic
|
from xiuren.meitu_dl import meitu_dowload_pic, meitu_dowload_pub_pic, meitu_dowload_heisi_pic
|
||||||
@@ -55,11 +60,27 @@ class Robot(Job):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.LOG = logging.getLogger("Robot")
|
self.LOG = logging.getLogger("Robot")
|
||||||
self.wxid = self.wcf.get_self_wxid()
|
self.wxid = self.wcf.get_self_wxid()
|
||||||
self.allContacts = self.getAllContacts()
|
self.allContacts = self.get_all_contacts()
|
||||||
|
self.LOG.info(f"DB+REDIS 连接池开始初始化")
|
||||||
|
# db 配置加载
|
||||||
|
self.db_pool = mysql.connector.pooling.MySQLConnectionPool(self.config.mariadb)
|
||||||
|
self.LOG.info(f"DB连接池加载完成: {self.config.mariadb}")
|
||||||
|
self.redis_pool = redis.ConnectionPool(self.config.redis)
|
||||||
|
self.LOG.info(f"REDIS连接池加载完成: {self.config.redis}")
|
||||||
|
|
||||||
self.groups = {} # 存储按group_id分组的消息列表,每个group_id最多保留10条消息
|
self.groups = {} # 存储按group_id分组的消息列表,每个group_id最多保留10条消息
|
||||||
GroupBotManager.load_local_cache()
|
GroupBotManager.load_local_cache()
|
||||||
|
# 消息存档模块初始化,自动完成入库动作
|
||||||
|
self.message_storage = MessageStorage(self.db_pool, self.redis_pool)
|
||||||
|
# 权限模块加载
|
||||||
self.gbm = GroupBotManager()
|
self.gbm = GroupBotManager()
|
||||||
self.gmc = GroupMemberChange(wcf)
|
# 群成员变更模块加载
|
||||||
|
self.gmc = GroupMemberChange(wcf, self.redis_pool)
|
||||||
|
# 点歌模块加载
|
||||||
|
self.music = BotMusic(wcf, self.gbm)
|
||||||
|
# 签到模块加载
|
||||||
|
self.signin = SignInSystem(wcf, self.gbm, self.allContacts, self.db_pool, self.redis_pool)
|
||||||
|
|
||||||
if ChatType.is_in_chat_types(chat_type):
|
if ChatType.is_in_chat_types(chat_type):
|
||||||
if chat_type == ChatType.TIGER_BOT.value and TigerBot.value_check(self.config.TIGERBOT):
|
if chat_type == ChatType.TIGER_BOT.value and TigerBot.value_check(self.config.TIGERBOT):
|
||||||
self.chat = TigerBot(self.config.TIGERBOT)
|
self.chat = TigerBot(self.config.TIGERBOT)
|
||||||
@@ -132,13 +153,13 @@ class Robot(Job):
|
|||||||
if cy.isChengyu(text):
|
if cy.isChengyu(text):
|
||||||
rsp = cy.getNext(text)
|
rsp = cy.getNext(text)
|
||||||
if rsp:
|
if rsp:
|
||||||
self.sendTextMsg(rsp, msg.roomid)
|
self.send_text_msg(rsp, msg.roomid)
|
||||||
status = True
|
status = True
|
||||||
elif flag in ["?", "?"]: # 查词
|
elif flag in ["?", "?"]: # 查词
|
||||||
if cy.isChengyu(text):
|
if cy.isChengyu(text):
|
||||||
rsp = cy.getMeaning(text)
|
rsp = cy.getMeaning(text)
|
||||||
if rsp:
|
if rsp:
|
||||||
self.sendTextMsg(rsp, msg.roomid)
|
self.send_text_msg(rsp, msg.roomid)
|
||||||
status = True
|
status = True
|
||||||
|
|
||||||
return status
|
return status
|
||||||
@@ -172,15 +193,15 @@ class Robot(Job):
|
|||||||
player_id = resp["player_id"]
|
player_id = resp["player_id"]
|
||||||
print(f"消息: {message}")
|
print(f"消息: {message}")
|
||||||
print(f"玩家ID: {player_id}")
|
print(f"玩家ID: {player_id}")
|
||||||
self.sendTextMsg(message, msg.roomid, msg.sender)
|
self.send_text_msg(message, msg.roomid, msg.sender)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"game_message_load error:{e}")
|
self.LOG.error(f"game_message_load error:{e}")
|
||||||
return True
|
return True
|
||||||
if q == "#今日百度新闻":
|
if q == "#今日百度新闻":
|
||||||
self.newsBaiduReport((msg.roomid if msg.from_group() else msg.sender))
|
self.news_baidu_report((msg.roomid if msg.from_group() else msg.sender))
|
||||||
return True
|
return True
|
||||||
elif q in ["nbc", "cnn", "abc", "fox", "bbc"]:
|
elif q in ["nbc", "cnn", "abc", "fox", "bbc"]:
|
||||||
self.newsEnReport(q, (msg.roomid if msg.from_group() else msg.sender))
|
self.news_en_report(q, (msg.roomid if msg.from_group() else msg.sender))
|
||||||
return True
|
return True
|
||||||
elif q == '#总结':
|
elif q == '#总结':
|
||||||
self.message_summary_robot((msg.roomid if msg.from_group() else msg.sender))
|
self.message_summary_robot((msg.roomid if msg.from_group() else msg.sender))
|
||||||
@@ -221,7 +242,7 @@ class Robot(Job):
|
|||||||
# 如果是群消息,并且群没开启AI,则不处理该动作
|
# 如果是群消息,并且群没开启AI,则不处理该动作
|
||||||
if msg.from_group() and self.gbm.get_group_permission(msg.roomid,
|
if msg.from_group() and self.gbm.get_group_permission(msg.roomid,
|
||||||
Feature.AI_CAPABILITY) == PermissionStatus.DISABLED:
|
Feature.AI_CAPABILITY) == PermissionStatus.DISABLED:
|
||||||
self.sendTextMsg("群AI功能未开启", msg.roomid, msg.sender)
|
self.send_text_msg("群AI功能未开启", msg.roomid, msg.sender)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
if msg.type == 1: # 只处理类型为1的消息提供的问题,引用@不予以对话
|
if msg.type == 1: # 只处理类型为1的消息提供的问题,引用@不予以对话
|
||||||
@@ -230,9 +251,9 @@ class Robot(Job):
|
|||||||
return True
|
return True
|
||||||
if rsp:
|
if rsp:
|
||||||
if msg.from_group():
|
if msg.from_group():
|
||||||
self.sendTextMsg(rsp, msg.roomid, msg.sender)
|
self.send_text_msg(rsp, msg.roomid, msg.sender)
|
||||||
else:
|
else:
|
||||||
self.sendTextMsg(rsp, msg.sender)
|
self.send_text_msg(rsp, msg.sender)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@@ -259,7 +280,7 @@ class Robot(Job):
|
|||||||
# 聊天记录入库动作:
|
# 聊天记录入库动作:
|
||||||
try:
|
try:
|
||||||
now_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
now_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
archive_message(msg.roomid, now_time, msg.sender, msg.content, msg.type, msg.extra)
|
self.message_storage.archive_message(msg.roomid, now_time, msg.sender, msg.content, msg.type, msg.extra)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"archive_message error: {e}")
|
self.LOG.error(f"archive_message error: {e}")
|
||||||
|
|
||||||
@@ -268,7 +289,7 @@ class Robot(Job):
|
|||||||
if msg.from_self():
|
if msg.from_self():
|
||||||
self.revoke_receive_message(msg)
|
self.revoke_receive_message(msg)
|
||||||
rsp = self.gbm.handle_command(msg.roomid, msg.content)
|
rsp = self.gbm.handle_command(msg.roomid, msg.content)
|
||||||
self.sendTextMsg(rsp, msg.roomid, msg.sender)
|
self.send_text_msg(rsp, msg.roomid, msg.sender)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"revoke_receive_message error: {e}")
|
self.LOG.error(f"revoke_receive_message error: {e}")
|
||||||
@@ -288,7 +309,7 @@ class Robot(Job):
|
|||||||
player_id = resp["player_id"]
|
player_id = resp["player_id"]
|
||||||
print(f"消息: {message}")
|
print(f"消息: {message}")
|
||||||
print(f"玩家ID: {player_id}")
|
print(f"玩家ID: {player_id}")
|
||||||
self.sendTextMsg(message, msg.roomid, msg.sender)
|
self.send_text_msg(message, msg.roomid, msg.sender)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"game_message_load error:{e}")
|
self.LOG.error(f"game_message_load error:{e}")
|
||||||
@@ -298,25 +319,25 @@ class Robot(Job):
|
|||||||
# 判断是否没有变化
|
# 判断是否没有变化
|
||||||
if "$NO_CHANGE$" not in result:
|
if "$NO_CHANGE$" not in result:
|
||||||
self.LOG.info(f"检测到群成员变化,进行相关内容输出:{result}")
|
self.LOG.info(f"检测到群成员变化,进行相关内容输出:{result}")
|
||||||
self.sendTextMsg(result, msg.roomid)
|
self.send_text_msg(result, msg.roomid)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"group_member_change error: {e}")
|
self.LOG.error(f"group_member_change error: {e}")
|
||||||
|
try:
|
||||||
|
self.music.get_music(message=msg)
|
||||||
|
except Exception as e:
|
||||||
|
self.LOG.error(f"get_music error: {e}")
|
||||||
|
|
||||||
if msg.is_at(self.wxid): # 被@
|
if msg.is_at(self.wxid): # 被@
|
||||||
self.toAt(msg)
|
self.toAt(msg)
|
||||||
|
|
||||||
else: # 其他消息
|
|
||||||
self.toChengyu(msg)
|
|
||||||
|
|
||||||
return # 处理完群聊信息,后面就不需要处理了
|
return # 处理完群聊信息,后面就不需要处理了
|
||||||
|
|
||||||
# 非群聊信息,按消息类型进行处理
|
# 非群聊信息,按消息类型进行处理
|
||||||
if msg.type == 37: # 好友请求
|
if msg.type == 37: # 好友请求
|
||||||
self.LOG.info(f"收到好友请求:{msg}")
|
self.LOG.info(f"收到好友请求:{msg}")
|
||||||
self.autoAcceptFriendRequest(msg)
|
self.auto_accept_friend_request(msg)
|
||||||
|
|
||||||
elif msg.type == 10000: # 系统信息
|
elif msg.type == 10000: # 系统信息
|
||||||
self.sayHiToNewFriend(msg)
|
self.say_hi_to_new_friend(msg)
|
||||||
|
|
||||||
elif msg.type == 0x01: # 文本消息
|
elif msg.type == 0x01: # 文本消息
|
||||||
# 让配置加载更灵活,自己可以更新配置。也可以利用定时任务更新。
|
# 让配置加载更灵活,自己可以更新配置。也可以利用定时任务更新。
|
||||||
@@ -326,15 +347,15 @@ class Robot(Job):
|
|||||||
self.gbm.load_local_cache()
|
self.gbm.load_local_cache()
|
||||||
self.LOG.info("已更新")
|
self.LOG.info("已更新")
|
||||||
if msg.content == "今日百度新闻":
|
if msg.content == "今日百度新闻":
|
||||||
self.newsBaiduReport()
|
self.news_baidu_report()
|
||||||
if msg.content == '聊天排行榜':
|
if msg.content == '聊天排行榜':
|
||||||
self.generateAndSendRanking()
|
self.generate_and_send_ranking()
|
||||||
if msg.content == '聊天数据入库':
|
if msg.content == '聊天数据入库':
|
||||||
self.messageCountToDB()
|
self.message_count_to_db()
|
||||||
if msg.content == 'PDF':
|
if msg.content == 'PDF':
|
||||||
self.generateSehuatangPdf()
|
self.generate_sehuatang_pdf()
|
||||||
if msg.content == 'GROUP_LIST':
|
if msg.content == 'GROUP_LIST':
|
||||||
self.sendTextMsg(self.gbm.get_group_list(), msg.sender)
|
self.send_text_msg(self.gbm.get_group_list(), msg.sender)
|
||||||
if msg.content.startswith('#加群配置'):
|
if msg.content.startswith('#加群配置'):
|
||||||
# msg_content = "# 加群配置|add 原生鱼 xxx@room"
|
# msg_content = "# 加群配置|add 原生鱼 xxx@room"
|
||||||
parts = msg.content.split('|')
|
parts = msg.content.split('|')
|
||||||
@@ -344,8 +365,8 @@ class Robot(Job):
|
|||||||
resp = process_command(after_pipe)
|
resp = process_command(after_pipe)
|
||||||
else:
|
else:
|
||||||
resp = process_command("help")
|
resp = process_command("help")
|
||||||
self.sendTextMsg(resp, msg.sender)
|
self.send_text_msg(resp, msg.sender)
|
||||||
self.sendTextMsg(f"指令:{msg.content} 已执行", msg.sender)
|
self.send_text_msg(f"指令:{msg.content} 已执行", msg.sender)
|
||||||
else:
|
else:
|
||||||
self.toChitchat(msg) # 闲聊
|
self.toChitchat(msg) # 闲聊
|
||||||
|
|
||||||
@@ -376,7 +397,7 @@ class Robot(Job):
|
|||||||
self.wcf.enable_receiving_msg()
|
self.wcf.enable_receiving_msg()
|
||||||
Thread(target=innerProcessMsg, name="GetMessage", args=(self.wcf,), daemon=True).start()
|
Thread(target=innerProcessMsg, name="GetMessage", args=(self.wcf,), daemon=True).start()
|
||||||
|
|
||||||
def sendTextMsg(self, msg: str, receiver: str, at_list: str = "") -> None:
|
def send_text_msg(self, msg: str, receiver: str, at_list: str = "") -> None:
|
||||||
""" 发送消息
|
""" 发送消息
|
||||||
:param msg: 消息字符串
|
:param msg: 消息字符串
|
||||||
:param receiver: 接收人wxid或者群id
|
:param receiver: 接收人wxid或者群id
|
||||||
@@ -405,7 +426,7 @@ class Robot(Job):
|
|||||||
self.LOG.info(f"To {receiver}: {ats}\r{msg}")
|
self.LOG.info(f"To {receiver}: {ats}\r{msg}")
|
||||||
self.wcf.send_text(f"{ats}\n\n{msg}", receiver, at_list)
|
self.wcf.send_text(f"{ats}\n\n{msg}", receiver, at_list)
|
||||||
|
|
||||||
def getAllContacts(self) -> dict:
|
def get_all_contacts(self) -> dict:
|
||||||
"""
|
"""
|
||||||
获取联系人(包括好友、公众号、服务号、群成员……)
|
获取联系人(包括好友、公众号、服务号、群成员……)
|
||||||
格式: {"wxid": "NickName"}
|
格式: {"wxid": "NickName"}
|
||||||
@@ -413,7 +434,7 @@ class Robot(Job):
|
|||||||
contacts = self.wcf.query_sql("MicroMsg.db", "SELECT UserName, NickName FROM Contact;")
|
contacts = self.wcf.query_sql("MicroMsg.db", "SELECT UserName, NickName FROM Contact;")
|
||||||
return {contact["UserName"]: contact["NickName"] for contact in contacts}
|
return {contact["UserName"]: contact["NickName"] for contact in contacts}
|
||||||
|
|
||||||
def keepRunningAndBlockProcess(self) -> None:
|
def keep_running_and_block_process(self) -> None:
|
||||||
"""
|
"""
|
||||||
保持机器人运行,不让进程退出
|
保持机器人运行,不让进程退出
|
||||||
"""
|
"""
|
||||||
@@ -421,7 +442,7 @@ class Robot(Job):
|
|||||||
self.runPendingJobs()
|
self.runPendingJobs()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
def autoAcceptFriendRequest(self, msg: WxMsg) -> None:
|
def auto_accept_friend_request(self, msg: WxMsg) -> None:
|
||||||
try:
|
try:
|
||||||
xml = ET.fromstring(msg.content)
|
xml = ET.fromstring(msg.content)
|
||||||
v3 = xml.attrib["encryptusername"]
|
v3 = xml.attrib["encryptusername"]
|
||||||
@@ -432,12 +453,12 @@ class Robot(Job):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"同意好友出错:{e}")
|
self.LOG.error(f"同意好友出错:{e}")
|
||||||
|
|
||||||
def sayHiToNewFriend(self, msg: WxMsg) -> None:
|
def say_hi_to_new_friend(self, msg: WxMsg) -> None:
|
||||||
nickName = re.findall(r"你已添加了(.*),现在可以开始聊天了。", msg.content)
|
nickName = re.findall(r"你已添加了(.*),现在可以开始聊天了。", msg.content)
|
||||||
if nickName:
|
if nickName:
|
||||||
# 添加了好友,更新好友列表
|
# 添加了好友,更新好友列表
|
||||||
self.allContacts[msg.sender] = nickName[0]
|
self.allContacts[msg.sender] = nickName[0]
|
||||||
self.sendTextMsg(f"Hi {nickName[0]},我自动通过了你的好友请求。", msg.sender)
|
self.send_text_msg(f"Hi {nickName[0]},我自动通过了你的好友请求。", msg.sender)
|
||||||
|
|
||||||
def send_group_txt_message(self, msg: str, feature: Feature):
|
def send_group_txt_message(self, msg: str, feature: Feature):
|
||||||
try:
|
try:
|
||||||
@@ -446,7 +467,7 @@ class Robot(Job):
|
|||||||
return
|
return
|
||||||
for r in receivers:
|
for r in receivers:
|
||||||
if self.gbm.get_group_permission(r, feature) == PermissionStatus.ENABLED:
|
if self.gbm.get_group_permission(r, feature) == PermissionStatus.ENABLED:
|
||||||
self.sendTextMsg(msg, r)
|
self.send_text_msg(msg, r)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"send_group_txt_message:{feature.description} error:{e}")
|
self.LOG.error(f"send_group_txt_message:{feature.description} error:{e}")
|
||||||
|
|
||||||
@@ -497,28 +518,28 @@ class Robot(Job):
|
|||||||
|
|
||||||
# ============================================== 业务内容==========================================================
|
# ============================================== 业务内容==========================================================
|
||||||
|
|
||||||
def newsBaiduReportAuto(self) -> None:
|
def news_baidu_report_auto(self) -> None:
|
||||||
try:
|
try:
|
||||||
news = News().get_baidu_news()
|
news = News().get_baidu_news()
|
||||||
self.send_group_txt_message(news, Feature.DAILY_NEWS)
|
self.send_group_txt_message(news, Feature.DAILY_NEWS)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"newsBaiduReportAuto error:{e}")
|
self.LOG.error(f"newsBaiduReportAuto error:{e}")
|
||||||
|
|
||||||
def newsBaiduReport(self, sender: str = None) -> None:
|
def news_baidu_report(self, sender: str = None) -> None:
|
||||||
try:
|
try:
|
||||||
news = News().get_baidu_news()
|
news = News().get_baidu_news()
|
||||||
self.sendTextMsg(news, sender)
|
self.send_text_msg(news, sender)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"newsBaiduReport error:{e}")
|
self.LOG.error(f"newsBaiduReport error:{e}")
|
||||||
|
|
||||||
def newsEnReport(self, website, sender: str = None) -> None:
|
def news_en_report(self, website, sender: str = None) -> None:
|
||||||
try:
|
try:
|
||||||
news = News().get_eng_news(website)
|
news = News().get_eng_news(website)
|
||||||
self.sendTextMsg(news, sender)
|
self.send_text_msg(news, sender)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"newsEnReport error:{e}")
|
self.LOG.error(f"newsEnReport error:{e}")
|
||||||
|
|
||||||
def sendEpicFreeGames(self):
|
def send_epic_free_games(self):
|
||||||
try:
|
try:
|
||||||
if is_friday():
|
if is_friday():
|
||||||
games = get_free()
|
games = get_free()
|
||||||
@@ -526,13 +547,13 @@ class Robot(Job):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"sendEpicFreeGames error:{e}")
|
self.LOG.error(f"sendEpicFreeGames error:{e}")
|
||||||
|
|
||||||
def messageCountToDB(self):
|
def message_count_to_db(self):
|
||||||
try:
|
try:
|
||||||
write_to_db()
|
write_to_db()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"write_to_db error:{e}")
|
self.LOG.error(f"write_to_db error:{e}")
|
||||||
|
|
||||||
def generateSehuatangPdf(self):
|
def generate_sehuatang_pdf(self):
|
||||||
try:
|
try:
|
||||||
path = pdf_file_path()
|
path = pdf_file_path()
|
||||||
# 暂时只发4K群
|
# 暂时只发4K群
|
||||||
@@ -540,14 +561,14 @@ class Robot(Job):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"generateSehuatangPdf error:{e}")
|
self.LOG.error(f"generateSehuatangPdf error:{e}")
|
||||||
|
|
||||||
def generateAndSendRanking(self):
|
def generate_and_send_ranking(self):
|
||||||
try:
|
try:
|
||||||
receivers = self.gbm.get_group_list()
|
receivers = self.gbm.get_group_list()
|
||||||
if not receivers:
|
if not receivers:
|
||||||
return
|
return
|
||||||
for r in receivers:
|
for r in receivers:
|
||||||
if self.gbm.get_group_permission(r, Feature.DAILY_SUMMARY) == PermissionStatus.ENABLED:
|
if self.gbm.get_group_permission(r, Feature.DAILY_SUMMARY) == PermissionStatus.ENABLED:
|
||||||
self.sendTextMsg(generate_and_send_ranking(r, self.allContacts), r)
|
self.send_text_msg(generate_and_send_ranking(r, self.allContacts), r)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"SendRanking error:{e}")
|
self.LOG.error(f"SendRanking error:{e}")
|
||||||
|
|
||||||
@@ -555,11 +576,11 @@ class Robot(Job):
|
|||||||
try:
|
try:
|
||||||
if self.gbm.get_group_permission(sender, Feature.SUMMARY_CAPABILITY) == PermissionStatus.ENABLED:
|
if self.gbm.get_group_permission(sender, Feature.SUMMARY_CAPABILITY) == PermissionStatus.ENABLED:
|
||||||
self.LOG.info(f"群: {sender} 消息总结开始执行!")
|
self.LOG.info(f"群: {sender} 消息总结开始执行!")
|
||||||
content = get_messages(sender, self.allContacts)
|
content = self.message_storage.get_messages(sender, self.allContacts)
|
||||||
summary = message_summary(content)
|
summary = message_summary(content)
|
||||||
self.sendTextMsg(summary, sender)
|
self.send_text_msg(summary, sender)
|
||||||
else:
|
else:
|
||||||
self.sendTextMsg("群发言总结功能未开启", sender)
|
self.send_text_msg("群发言总结功能未开启", sender)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"message_summary_robot error:{e}")
|
self.LOG.error(f"message_summary_robot error:{e}")
|
||||||
|
|
||||||
@@ -574,7 +595,7 @@ class Robot(Job):
|
|||||||
player_id = rep["player_id"]
|
player_id = rep["player_id"]
|
||||||
print(f"消息: {message}")
|
print(f"消息: {message}")
|
||||||
print(f"玩家ID: {player_id}")
|
print(f"玩家ID: {player_id}")
|
||||||
self.sendTextMsg(message, gid, player_id)
|
self.send_text_msg(message, gid, player_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.LOG.error(f"message_summary_robot error:{e}")
|
self.LOG.error(f"message_summary_robot error:{e}")
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ class Feature(Enum):
|
|||||||
EPIC = 7, "EPIC自动播报" # 新增的功能
|
EPIC = 7, "EPIC自动播报" # 新增的功能
|
||||||
PIC = 8, "图来能力"
|
PIC = 8, "图来能力"
|
||||||
TASK_GAME = 9, "百科答题游戏"
|
TASK_GAME = 9, "百科答题游戏"
|
||||||
|
MUSIC = 10, "点歌功能"
|
||||||
|
|
||||||
def __new__(cls, value, description):
|
def __new__(cls, value, description):
|
||||||
obj = object.__new__(cls)
|
obj = object.__new__(cls)
|
||||||
|
|||||||
Reference in New Issue
Block a user