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()