NetEaseDSMonitor/inspect_monitor.py
2025-04-29 22:01:18 +08:00

388 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import json
import time
import requests
import logging
from datetime import datetime, timedelta
from threading import Lock
import signal
import sys
import threading
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('inspect_monitor.log'),
logging.StreamHandler()
]
)
# 增加log函数兼容自定义日志调用
def log(message):
try:
logging.info(f"[INSPECT] {message}")
except Exception as e:
print(f"日志记录失败: {str(e)}")
print(f"原始消息: {message}")
# 常量定义
INSPECT_API_URL = "https://api.cc.163.com/v1/inspectapi/forumtrack/tracklog/searchtracklog"
COEFFICIENT = 1.5 # CC审核平台的系数
HOURLY_DATA_FILE = "inspect_hourly.json"
DAILY_DATA_FILE = "inspect_daily.json"
COEFFICIENTS_CONFIG_FILE = "inspect_coefficients.json"
DEFAULT_COEFFICIENTS = {"default": 1.5}
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
coefficients_lock = Lock()
def handle_exit(signum, frame):
logging.info(f"收到退出信号({signum}),即将退出")
sys.exit(0)
signal.signal(signal.SIGTERM, handle_exit)
signal.signal(signal.SIGINT, handle_exit)
def get_inspect_stats(username, cookie, start_time, end_time):
"""获取CC审核平台的统计数据"""
try:
# 每次统计前主动加载系数,确保用到最新
load_coefficients()
# 准备请求数据
data = {
"data": {
"form": {
"operator": f"{username.lower()}@mail.go",
"startTime": start_time,
"endTime": end_time,
"tid": "",
"pid": ""
},
"page": 1,
"pageSize": 500
}
}
# 设置请求头
headers = {
"accept": "application/json, text/plain, */*",
"content-type": "text/plain",
"cookie": cookie,
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
}
# 发送请求
response = requests.post(INSPECT_API_URL, headers=headers, json=data)
response.raise_for_status()
# 解析响应
result = response.json()
if result.get("code") == "OK":
total = result.get("data", {}).get("result", {}).get("total", 0)
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 使用从在线链接获取的系数
with coefficients_lock:
current_coefficient = COEFFICIENTS.get('default', 1.5)
return {
"total": total,
"weighted_total": total * current_coefficient,
"timestamp": int(time.time()),
"update_time": current_time
}
else:
logging.error(f"获取CC审核平台数据失败: {result.get('msg')}")
return None
except Exception as e:
logging.error(f"获取CC审核平台数据时发生错误: {str(e)}")
return None
def save_stats(stats, file_path):
"""保存统计数据到文件"""
try:
with open(file_path, 'w') as f:
json.dump(stats, f)
except Exception as e:
logging.error(f"保存统计数据时发生错误: {str(e)}")
def load_stats(file_path):
"""从文件加载统计数据"""
try:
if os.path.exists(file_path):
with open(file_path, 'r') as f:
return json.load(f)
except Exception as e:
logging.error(f"加载统计数据时发生错误: {str(e)}")
return {"stats": []}
def update_hourly_stats(username, cookie):
"""更新小时统计数据"""
now = datetime.now()
start_time = now.strftime("%Y/%m/%d %H:00:00")
end_time = now.strftime("%Y/%m/%d %H:59:59")
stats = get_inspect_stats(username, cookie, start_time, end_time)
if stats:
hourly_data = load_stats(HOURLY_DATA_FILE)
# 移除超过24小时的数据
current_time = int(time.time())
hourly_data["stats"] = [
stat for stat in hourly_data["stats"]
if current_time - stat["timestamp"] <= 24 * 3600
]
# 添加新数据
hourly_data["stats"].append(stats)
save_stats(hourly_data, HOURLY_DATA_FILE)
logging.info(f"成功更新小时统计数据: {stats}")
def update_daily_stats(username, cookie):
"""更新日统计数据"""
now = datetime.now()
start_time = now.strftime("%Y/%m/%d 00:00:00")
end_time = now.strftime("%Y/%m/%d 23:59:59")
stats = get_inspect_stats(username, cookie, start_time, end_time)
if stats:
daily_data = load_stats(DAILY_DATA_FILE)
# 移除超过7天的数据
current_time = int(time.time())
daily_data["stats"] = [
stat for stat in daily_data["stats"]
if current_time - stat["timestamp"] <= 7 * 24 * 3600
]
# 添加新数据
daily_data["stats"].append(stats)
save_stats(daily_data, DAILY_DATA_FILE)
logging.info(f"成功更新日统计数据: {stats}")
def fetch_and_save_coefficients(url):
"""从在线服务器获取系数配置并保存到本地"""
max_retries = 3
retry_delay = 5 # 重试间隔(秒)
for attempt in range(max_retries):
try:
# 尝试不使用代理直接获取
try:
response = requests.get(url, timeout=10, proxies={'http': None, 'https': None}, verify=False)
except:
# 如果直接获取失败,尝试使用系统代理
proxies = {
'http': os.environ.get('HTTP_PROXY', ''),
'https': os.environ.get('HTTPS_PROXY', '')
}
response = requests.get(url, timeout=10, proxies=proxies, verify=False)
if response.status_code == 200:
loaded_coefficients = response.json()
# 更新系数
COEFFICIENTS.update(loaded_coefficients)
# 保存到本地文件
with open(COEFFICIENTS_CONFIG_FILE, 'w', encoding='utf-8') as f:
json.dump(loaded_coefficients, f, indent=4, ensure_ascii=False)
log(f"从服务器获取系数: {loaded_coefficients}")
return True
else:
log(f"获取在线系数配置失败HTTP状态码: {response.status_code}")
if attempt < max_retries - 1:
log(f"{attempt + 1}次重试失败,{retry_delay}秒后重试...")
time.sleep(retry_delay)
continue
return False
except Exception as e:
log(f"获取在线系数配置时发生错误: {str(e)}")
if attempt < max_retries - 1:
log(f"{attempt + 1}次重试失败,{retry_delay}秒后重试...")
time.sleep(retry_delay)
continue
return False
def load_coefficients():
"""从在线链接获取系数配置,如果获取失败则使用默认配置"""
global COEFFICIENTS
try:
with coefficients_lock:
url = "http://scripts.ui-beam.com:5000/NetEaseDSMonitor/config/inspect_coefficients.json"
# 检查本地文件是否存在
local_config_exists = os.path.exists(COEFFICIENTS_CONFIG_FILE)
# 如果是首次运行或需要强制更新
if not local_config_exists:
log("首次运行,从在线服务器获取系数配置")
if not fetch_and_save_coefficients(url):
log("首次获取系数配置失败,使用默认配置")
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
return
# 读取本地配置
try:
with open(COEFFICIENTS_CONFIG_FILE, 'r', encoding='utf-8') as f:
local_coefficients = json.load(f)
except Exception as e:
log(f"读取本地系数配置失败: {str(e)}")
local_coefficients = None
# 尝试获取在线配置
try:
response = requests.get(url, timeout=10, proxies={'http': None, 'https': None}, verify=False)
if response.status_code == 200:
online_coefficients = response.json()
# 比较配置是否发生变化
if local_coefficients != online_coefficients:
log("检测到系数配置发生变化,更新本地配置")
if fetch_and_save_coefficients(url):
log("系数配置更新成功")
else:
log("系数配置更新失败,继续使用本地配置")
else:
log("系数配置未发生变化,使用本地配置")
else:
log(f"获取在线系数配置失败HTTP状态码: {response.status_code}")
except Exception as e:
log(f"检查在线系数配置时发生错误: {str(e)}")
# 使用本地配置
if local_coefficients:
COEFFICIENTS.update(local_coefficients)
log(f"从本地从加载系数: {local_coefficients}")
else:
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
except Exception as e:
log(f"加载系数配置失败: {str(e)}")
COEFFICIENTS = DEFAULT_COEFFICIENTS.copy()
def monitor_config_thread():
"""监控配置文件变化线程"""
log("配置监控线程启动")
last_check_time = 0
check_interval = 1800 # 30分钟
while True:
try:
current_time = time.time()
# 检查是否需要更新配置
if current_time - last_check_time >= check_interval:
log("开始检查系数配置更新")
load_coefficients()
last_check_time = current_time
time.sleep(60) # 每分钟检查一次时间
except Exception as e:
log(f"配置监控线程异常: {str(e)}")
time.sleep(60) # 发生异常时等待1分钟后重试
def send_global_message(message):
"""发送全局消息提示"""
try:
# 将消息写入到全局消息文件
message_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'global_messages.json')
messages = []
if os.path.exists(message_file):
with open(message_file, 'r', encoding='utf-8') as f:
messages = json.load(f)
# 添加新消息
messages.append({
'timestamp': int(time.time()),
'message': message,
'type': 'error'
})
# 只保留最近100条消息
if len(messages) > 100:
messages = messages[-100:]
# 保存消息
with open(message_file, 'w', encoding='utf-8') as f:
json.dump(messages, f, ensure_ascii=False)
except Exception as e:
log(f"发送全局消息失败: {str(e)}")
def main():
"""主函数"""
logging.info("CC审核平台监控系统启动")
# 解析命令行参数
check_now = False
for arg in sys.argv:
if arg == "--check-now":
check_now = True
logging.info("收到立即检查参数")
# 从环境变量获取凭据
username = os.environ.get('INSPECT_USERNAME')
cookie = os.environ.get('INSPECT_COOKIE')
if not username or not cookie:
logging.error("未设置CC审核平台凭据")
return
if check_now:
logging.info("开始执行手动检查")
update_hourly_stats(username, cookie)
logging.info("手动检查完成")
sys.exit(0)
# 启动小时和日数据监控线程
def hourly_update_thread():
while True:
try:
update_hourly_stats(username, cookie)
logging.info("已完成小时统计数据更新")
time.sleep(120)
except Exception as e:
logging.error(f"小时数据更新线程错误: {str(e)}")
time.sleep(60)
def daily_update_thread():
last_daily_check = None
while True:
try:
now = datetime.now()
if last_daily_check is None or (now - last_daily_check).total_seconds() >= 3600:
update_daily_stats(username, cookie)
last_daily_check = now
logging.info("已完成日统计数据更新")
time.sleep(300)
except Exception as e:
logging.error(f"日数据更新线程错误: {str(e)}")
time.sleep(60)
hourly_thread = threading.Thread(target=hourly_update_thread)
hourly_thread.daemon = True
hourly_thread.start()
daily_thread = threading.Thread(target=daily_update_thread)
daily_thread.daemon = True
daily_thread.start()
# 启动配置监控线程
config_thread = threading.Thread(target=monitor_config_thread)
config_thread.daemon = True
config_thread.start()
# 保持主线程运行
try:
while True:
time.sleep(10)
except KeyboardInterrupt:
logging.info("程序被用户中断")
except Exception as e:
logging.error(f"主线程异常: {str(e)}")
finally:
logging.info("CC审核平台监控系统关闭")
sys.exit(0)
if __name__ == "__main__":
main()