Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01d65972fd | ||
|
|
b1334fc06a | ||
|
|
918c73b5dc | ||
|
|
28f04a4eb9 | ||
|
|
26328e66c4 | ||
|
|
1d85837e79 | ||
|
|
ba8e2f1625 | ||
|
|
6b809138e5 | ||
|
|
6f4e871c7c | ||
|
|
fe2c9de80b | ||
|
|
6c0a589395 | ||
|
|
42a128fd6b | ||
|
|
a891f2017a | ||
|
|
66fdfb1908 | ||
|
|
aa2874fdcd | ||
|
|
120dd264c2 | ||
|
|
455f98fafd | ||
|
|
2c1041ebed | ||
|
|
0af3ff5cd8 | ||
|
|
6faa7b2c2a | ||
|
|
873b6996ca | ||
|
|
84832395bd | ||
|
|
96a7400be8 | ||
|
|
ba565978c6 | ||
|
|
b53032cc92 | ||
|
|
e96eacd6f8 | ||
|
|
4cac51673a | ||
|
|
be75e5b65c | ||
|
|
c7ece6620c | ||
|
|
7e9da4b82a | ||
|
|
c657c92b27 | ||
|
|
d43163703e | ||
|
|
1150450718 | ||
|
|
df6483afa8 | ||
|
|
29de2eadf8 | ||
|
|
318689f163 |
44
.github/workflows/daily_keywords.yml
vendored
Normal file
44
.github/workflows/daily_keywords.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Daily Trends Factory
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 每天 UTC 18:00 运行 (北京时间凌晨 02:00)
|
||||
- cron: '0 18 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update-trends:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Execute Trends Engine
|
||||
run: python scripts/fetch_trends.py
|
||||
|
||||
- name: Commit and Push
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
git add data/keywords/
|
||||
|
||||
# 防御机制:如果没有新数据,就静默退出,不产生空提交
|
||||
if git diff --staged --quiet; then
|
||||
echo "No changes, skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 策略:放弃危险的 amend 强制覆盖,采用带日期的标准安全提交
|
||||
git commit -m "chore(data): 🤖 自动机兵:刷新全战区热点词库 [$(date +'%Y-%m-%d')]"
|
||||
git push origin main
|
||||
10
README.md
10
README.md
@@ -18,9 +18,13 @@
|
||||
|
||||
- 🏭 **自动化指纹兵工厂 (Automated UA Factory)**:依托 GitHub Actions CI/CD 流水线,每月 1 日无人值守全自动生成 4000+ 带绝对物理分区的真实终端设备数据。配合边缘节点的守护进程静默拉取,实现千万级指纹资产的“自动驾驶”级演进。
|
||||
|
||||
- 📡 **OTA 动态活体词库 (Dynamic Trends)**:v3.3.0 跨时代跃升。彻底废弃静态搜索词,引入 GitHub Actions 云端流水线。每天自动抓取美、日、德、英等全战区当日 Google 热搜榜单,并通过边缘节点每日静默同步,让您的 IP 搜索行为永远贴合当地当天的真实网络脉搏。
|
||||
|
||||
- 🔀 **智能错峰调度 (Thundering Herd Mitigation)**:v3.3.0 架构升级。首创节点部署时间戳锚定逻辑。边缘节点按需智能分频(每日拉取几百行轻量词库,每月按 30 天周期错峰拉取千万级指纹库),完美化解“惊群效应”,彻底抹平统一升级时的数据并发特征,隐匿于无形。
|
||||
|
||||
- 🖧 **底层路由死锁 (Hard-Bind Routing)**:v3.2.1 热修复升级。底层探测引擎强力接管 curl 核心参数 (--interface),强制将发出的每一滴伪装流量死死绑定在您设定的物理网卡或隧道 IP 上,彻底杜绝双栈或多网卡环境下的流量溢出漏洞。
|
||||
|
||||
- 🎯 **多级容灾与高精度探针 (High-Precision Probe)**:v3.2.2 底层重构。重写战报模块与底层协议自适应逻辑,植入多级 ISP 容灾探针链路,并按“底层数据共识原则”智能清洗冗余 AS 号。确保在纯 V6、隧道或弱网环境下,数据获取依然 100% 精准畅通。
|
||||
- 🎯 **多级容灾与高精度探针 (High-Precision Probe)**:v3.2.2 底层重构。重写战报模块与底层协议自适应逻辑,植入多级 ISP 容灾探针链路,并按“底层数据共识原则”智能清洗冗余 AS 号。确保在纯 V6、隧道或弱网环境下,数据获取依然 100% 精准畅通。
|
||||
|
||||
- 🔄 **平滑热更新装甲 (Smooth Upgrade Engine)**:v3.2.2 体验进化。全系植入状态机嗅探逻辑。无论是 Master 司令部还是 Agent 边缘节点,再次执行部署脚本时将自动识别并继承历史配置、SQLite 数据库与锚定 IP,一键回车即可瞬间完成无损换代,告别繁琐的重复配置。
|
||||
|
||||
@@ -58,7 +62,7 @@
|
||||
|
||||
## 🚀 极速部署 (Quick Start)
|
||||
|
||||
v3.2.x 提供了两种接入模式,请根据您的战术需求选择:
|
||||
v3.3.x 提供了两种接入模式,请根据您的战术需求选择:
|
||||
|
||||
### 🔹 模式 A:官方公共模式 (最简、推荐)
|
||||
**适合不想折腾、只想快速养护 IP 的新兵。**
|
||||
@@ -86,7 +90,7 @@ bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/i
|
||||
```
|
||||
3. **激活节点**:同上,将暗号转发给您自己的机器人即可。
|
||||
|
||||
### ⚠️ 平滑升级指引 (Upgrade to v3.2.2)
|
||||
### ⚠️ 平滑升级指引 (Upgrade to v3.3.0)
|
||||
|
||||
得益于 **v3.2.2 全新引入的平滑热更新引擎 (Smooth Upgrade Engine)**,系统升级现已变得极其优雅与安全。
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程 V3.0.3)
|
||||
# 脚本名称: agent_daemon.sh (受控节点 Webhook 守护进程 v3.4.0 版本锚点版)
|
||||
# 核心功能: 智能防打扰注册、进程自检、模块级路由分发(403拦截)
|
||||
# ==========================================================
|
||||
|
||||
@@ -17,21 +17,27 @@ source "$CONFIG_FILE"
|
||||
|
||||
# 默认 Webhook 监听端口
|
||||
AGENT_PORT=${AGENT_PORT:-9527}
|
||||
NODE_NAME=$(hostname | cut -c 1-15)
|
||||
# [v3.4.0 核心] 统一采用防 Markdown 崩溃的中划线连接符
|
||||
IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||
NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}"
|
||||
|
||||
# --- [重点升级 1: 守护进程防冲突自检] ---
|
||||
if pgrep -f "webhook.py $AGENT_PORT" > /dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 1. [v3.0.1修复] 严格按照 install.sh 锁定的网络协议 (v4/v6) 获取 IP
|
||||
# 1. 尝试获取实时公网 IP
|
||||
RAW_IP=$(curl -${IP_PREF:-4} -s -m 5 api.ip.sb/ip | tr -d '[:space:]')
|
||||
|
||||
# 为新获取到的 v6 自动加方括号,以确保与之前锁定的格式对齐比对
|
||||
if [[ "$RAW_IP" == *":"* ]] && [[ "$RAW_IP" != *"["* ]]; then
|
||||
AGENT_IP="[${RAW_IP}]"
|
||||
# [v3.3.1 修改] 为新获取到的 v6 自动加方括号;如果网络波动没抓到,强制信任本地 config 中的公网面孔
|
||||
if [ -n "$RAW_IP" ]; then
|
||||
if [[ "$RAW_IP" == *":"* ]] && [[ "$RAW_IP" != *"["* ]]; then
|
||||
AGENT_IP="[${RAW_IP}]"
|
||||
else
|
||||
AGENT_IP="$RAW_IP"
|
||||
fi
|
||||
else
|
||||
AGENT_IP="$RAW_IP"
|
||||
AGENT_IP="${PUBLIC_IP:-${BIND_IP:-Unknown}}"
|
||||
fi
|
||||
|
||||
if [ -n "$AGENT_IP" ]; then
|
||||
@@ -200,8 +206,13 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
||||
if lines:
|
||||
log_data = html.escape("".join(lines[-15:]))
|
||||
|
||||
node_name = subprocess.check_output(['hostname']).decode('utf-8').strip()[:15]
|
||||
text_msg = f"📄 <b>[{node_name}] 实时运行日志:</b>\n<pre><code>{log_data}</code></pre>"
|
||||
# [v3.4.0 核心] 获取版本与主机名
|
||||
local_ver = config.get('AGENT_VERSION', '未知')
|
||||
node_hostname = subprocess.check_output(['hostname']).decode('utf-8').strip()[:10]
|
||||
ip_hash = hashlib.md5(config.get('PUBLIC_IP', '127.0.0.1').encode()).hexdigest()[:4].upper()
|
||||
full_node_name = f"{node_hostname}-{ip_hash}"
|
||||
|
||||
text_msg = f"📄 <b>[{full_node_name}] 实时日志 (v{local_ver}):</b>\n<pre><code>{log_data}</code></pre>"
|
||||
|
||||
data = urllib.parse.urlencode({
|
||||
'chat_id': config.get('CHAT_ID', ''),
|
||||
|
||||
169
core/install.sh
169
core/install.sh
@@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 v3.2.3 - Global Nexus)
|
||||
# 核心功能: 区域选择、模块按需开启、官方机器人一键配置、平滑热更新
|
||||
# 脚本名称: install.sh (IP-Sentinel 分布式边缘节点部署脚本 v3.4.0 - OTA 活体引擎)
|
||||
# 核心功能: 区域选择、模块按需开启、官方机器人一键配置、平滑热更新、版本状态机路由
|
||||
# ==========================================================
|
||||
|
||||
# 你的 GitHub 仓库 Raw 数据直链前缀
|
||||
@@ -12,8 +12,17 @@ REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||
INSTALL_DIR="/opt/ip_sentinel"
|
||||
CONFIG_FILE="${INSTALL_DIR}/config.conf"
|
||||
|
||||
# [v3.4.0 核心: 全局版本控制锚点]
|
||||
TARGET_VERSION="3.4.0"
|
||||
|
||||
# 轻量级版本号比对函数 (例如: version_lt "3.3.1" "3.4.0" 返回 true)
|
||||
version_lt() {
|
||||
test "$(printf '%s\n' "$1" "$2" | sort -V | head -n 1)" = "$1" && test "$1" != "$2"
|
||||
}
|
||||
|
||||
echo "========================================================"
|
||||
echo " 🛡️ 欢迎使用 IP-Sentinel (边缘节点 Edge Agent)"
|
||||
echo " 当前安装包版本: v${TARGET_VERSION}"
|
||||
echo "========================================================"
|
||||
|
||||
# 1. 依赖检查与安装 (新增 python3 用于轻量级 Webhook 服务)
|
||||
@@ -307,13 +316,34 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# 终极修复:为 IPv6 自动穿上防护装甲(方括号),解决 Master 拼接 URL 报错问题
|
||||
# ================== [v3.3.1 核心重构: 身份剥离与双栈实弹嗅探] ==================
|
||||
# 1. 固化对外通讯身份 (自动穿透方括号护甲)
|
||||
if [[ "$PUBLIC_IP" == *":"* ]] && [[ "$PUBLIC_IP" != *"["* ]]; then
|
||||
BIND_IP="[${PUBLIC_IP}]"
|
||||
SAFE_PUBLIC_IP="[${PUBLIC_IP}]"
|
||||
else
|
||||
BIND_IP="$PUBLIC_IP"
|
||||
SAFE_PUBLIC_IP="$PUBLIC_IP"
|
||||
fi
|
||||
echo -e "\033[32m✅ 哨兵锚点已永久锁定至: $BIND_IP\033[0m"
|
||||
|
||||
# 2. 实弹打靶测试 (NAT 环境嗅探与双栈自适应)
|
||||
echo -n "🕵️ 正在进行出站链路试射 (NAT环境与双栈嗅探)..."
|
||||
RAW_TEST_IP=$(echo "$SAFE_PUBLIC_IP" | tr -d '[]')
|
||||
|
||||
# 智能切换靶机:V6 机器打 Cloudflare V6 节点,V4 机器打 1.1.1.1
|
||||
if [[ "$RAW_TEST_IP" == *":"* ]]; then
|
||||
TEST_TARGET="https://[2606:4700:4700::1111]"
|
||||
else
|
||||
TEST_TARGET="https://1.1.1.1"
|
||||
fi
|
||||
|
||||
# 执行实弹试射
|
||||
if curl --interface "$RAW_TEST_IP" -sI -m 3 "$TEST_TARGET" >/dev/null 2>&1; then
|
||||
echo -e " \033[32m✅ 原生直连,物理网卡死锁已激活。\033[0m"
|
||||
BIND_IP="$SAFE_PUBLIC_IP"
|
||||
else
|
||||
echo -e " \033[33m⚠️ 发现 NAT/虚拟路由架构,自动卸除网卡枷锁,交由内核路由。\033[0m"
|
||||
BIND_IP=""
|
||||
fi
|
||||
echo -e "\033[32m✅ 哨兵对外联络点已永久锁定至: $SAFE_PUBLIC_IP\033[0m"
|
||||
# ========================================================================
|
||||
|
||||
# 5. 远程拉取冷数据并解析固化
|
||||
@@ -333,9 +363,10 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
||||
LANG_PARAMS=$(jq -r '.google_module.lang_params' "$REGION_JSON_FILE")
|
||||
VALID_URL_SUFFIX=$(jq -r '.google_module.valid_url_suffix' "$REGION_JSON_FILE")
|
||||
|
||||
# 写入本地静态配置文件
|
||||
# 写入本地静态配置文件 (v3.4.0 引入版本锚点)
|
||||
cat > "$CONFIG_FILE" << EOF
|
||||
# IP-Sentinel 本地固化配置 (生成时间: $(date '+%Y-%m-%d %H:%M:%S'))
|
||||
AGENT_VERSION="$TARGET_VERSION"
|
||||
REGION_CODE="$REGION_CODE"
|
||||
REGION_NAME="$REGION_NAME"
|
||||
BASE_LAT="$BASE_LAT"
|
||||
@@ -354,8 +385,9 @@ AGENT_PORT="$AGENT_PORT"
|
||||
INSTALL_DIR="$INSTALL_DIR"
|
||||
LOG_FILE="${INSTALL_DIR}/logs/sentinel.log"
|
||||
|
||||
# [v3.0.1新增修改 2: 网络栈锚点锁定配置,供其他脚本读取]
|
||||
# [v3.3.1修改: 双核身份剥离配置]
|
||||
IP_PREF="$IP_PREF"
|
||||
PUBLIC_IP="$SAFE_PUBLIC_IP"
|
||||
BIND_IP="$BIND_IP"
|
||||
EOF
|
||||
|
||||
@@ -366,6 +398,45 @@ EOF
|
||||
fi
|
||||
# 🛑 拦截块结束 (全套交互配置跳过完毕)
|
||||
|
||||
# ================== [v3.3.1 核心修复: 老节点配置无损热迁移] ==================
|
||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||
if ! grep -q "PUBLIC_IP=" "$CONFIG_FILE"; then
|
||||
echo -e "\n🔄 [平滑迁移] 正在对老节点进行 v3.3.1 双核身份架构升级..."
|
||||
|
||||
# 重新抓取公网面孔 (应对老节点 BIND_IP 可能已被手动清空的情况)
|
||||
MIGRATE_IP=$(curl -${IP_PREF:-4} -s -m 5 api.ip.sb/ip | tr -d '[:space:]')
|
||||
[[ "$MIGRATE_IP" == *":"* ]] && [[ "$MIGRATE_IP" != *"["* ]] && MIGRATE_IP="[${MIGRATE_IP}]"
|
||||
|
||||
echo -n "🕵️ 正在进行补发链路试射 (NAT与双栈嗅探)..."
|
||||
RAW_TEST_IP=$(echo "$MIGRATE_IP" | tr -d '[]')
|
||||
if [[ "$RAW_TEST_IP" == *":"* ]]; then
|
||||
TEST_TARGET="https://[2606:4700:4700::1111]"
|
||||
else
|
||||
TEST_TARGET="https://1.1.1.1"
|
||||
fi
|
||||
|
||||
if curl --interface "$RAW_TEST_IP" -sI -m 3 "$TEST_TARGET" >/dev/null 2>&1; then
|
||||
echo -e " \033[32m✅ 原生直连,网卡死锁已继承。\033[0m"
|
||||
NEW_BIND_IP="$MIGRATE_IP"
|
||||
else
|
||||
echo -e " \033[33m⚠️ 发现 NAT 架构,已自动卸除老版本的物理枷锁。\033[0m"
|
||||
NEW_BIND_IP=""
|
||||
fi
|
||||
|
||||
# 动态修改旧配置文件 (更新 BIND_IP,追加 PUBLIC_IP)
|
||||
sed -i "s/^BIND_IP=.*/BIND_IP=\"$NEW_BIND_IP\"/" "$CONFIG_FILE"
|
||||
echo "PUBLIC_IP=\"$MIGRATE_IP\"" >> "$CONFIG_FILE"
|
||||
|
||||
# 刷新当前安装脚本的环境变量,防止底部代码报错
|
||||
SAFE_PUBLIC_IP="$MIGRATE_IP"
|
||||
BIND_IP="$NEW_BIND_IP"
|
||||
else
|
||||
# 如果是未来再升级,配置文件已是最新,直接提取变量供安装脚本尾部使用
|
||||
SAFE_PUBLIC_IP=$(grep "^PUBLIC_IP=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||
fi
|
||||
fi
|
||||
# ========================================================================
|
||||
|
||||
# 6. 拉取全套组件 (按需下载,绝不浪费空间)
|
||||
echo -e "\n[6/7] 正在根据模块开关部署核心引擎与热数据..."
|
||||
# 确保目录在升级模式下也能被正确建立
|
||||
@@ -404,8 +475,11 @@ crontab -l 2>/dev/null | grep -v "ip_sentinel" > /tmp/cron_backup
|
||||
|
||||
# 核心养护模块: 每 30 分钟触发一次
|
||||
echo "*/30 * * * * ${INSTALL_DIR}/core/runner.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
||||
# 养料更新模块: 每周日凌晨 3 点静默去云端更新热数据
|
||||
echo "0 3 * * 0 ${INSTALL_DIR}/core/updater.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
||||
# 养料更新模块: (v3.3.0升级) 每天凌晨 3 点触发,由中枢自动进行分频调度
|
||||
echo "0 3 * * * ${INSTALL_DIR}/core/updater.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
||||
|
||||
# [v3.3.0 新增] 初始化 UA 指纹库更新时间戳,确立 30 天滚动周期的计算锚点
|
||||
echo $(date +%s) > "${INSTALL_DIR}/core/.ua_last_update"
|
||||
|
||||
# 如果配置了联控,启动 Webhook 与战报任务
|
||||
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||
@@ -414,8 +488,8 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||
|
||||
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP,直接使用我们上方锁定的 BIND_IP]
|
||||
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
|
||||
# [修复竞态]: 提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的抢跑推送
|
||||
echo "$BIND_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||
# [修复竞态]: 提前写入公网 IP 缓存,彻底阻断 agent_daemon 首次启动时的抢跑推送
|
||||
echo "$SAFE_PUBLIC_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||
|
||||
# 双保险守护进程看门狗
|
||||
echo "@reboot nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
|
||||
@@ -428,32 +502,65 @@ fi
|
||||
crontab /tmp/cron_backup
|
||||
rm -f /tmp/cron_backup
|
||||
|
||||
# ================== [v3.2.2 优化: 战报通知分流 (注册/升级)] ==================
|
||||
# ================== [v3.4.0 核心: 状态机驱动的热更新路由] ==================
|
||||
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||
NODE_NAME=$(hostname | cut -c 1-15)
|
||||
# 构造当前节点的唯一代号 (v3.3.2引入的防撞甲,已修正连接符)
|
||||
IP_HASH=$(echo "${SAFE_PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||
NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}"
|
||||
|
||||
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${SAFE_PUBLIC_IP}|${AGENT_PORT}"
|
||||
|
||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||
echo -e "\n📡 正在向指挥部发送升级成功战报..."
|
||||
curl -s -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
-d "parse_mode=Markdown" \
|
||||
-d "text=✨ *IP-Sentinel 引擎热更新完成!*
|
||||
📍 节点:\`${NODE_NAME}\`
|
||||
🌐 IP:\`${BIND_IP}\`
|
||||
🚀 状态:v3.2.2 协议自适应与高精度探针已就绪" >/dev/null 2>&1
|
||||
echo -e "\033[32m✅ 升级成功通知已推送到您的 Telegram!\033[0m"
|
||||
else
|
||||
echo -e "\n📡 正在向指挥部发送注册暗号..."
|
||||
# 构造注册暗号 (V3.1.3 协议升级: 携带 REGION_CODE 大区标识)
|
||||
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${BIND_IP}|${AGENT_PORT}"
|
||||
# 读取本地老版本号,如果没有则视为远古版本 v3.3.1
|
||||
OLD_VERSION=$(grep "^AGENT_VERSION=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||
[ -z "$OLD_VERSION" ] && OLD_VERSION="3.3.1"
|
||||
|
||||
# 执行主动推送
|
||||
# [路由表 1]: 跨代兼容 (老版本 < v3.3.2)
|
||||
# 必须强制下发带有 #REGISTER# 的警告,引导长官重新同步哈希身份
|
||||
if version_lt "$OLD_VERSION" "3.3.2"; then
|
||||
echo -e "\n📡 [路由枢纽] 正在执行跨代架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
||||
curl -s -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
-d "parse_mode=Markdown" \
|
||||
-d "text=✨ *IP-Sentinel 引擎热更新完成!*
|
||||
📍 节点:\`${NODE_NAME}\`
|
||||
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
||||
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署
|
||||
|
||||
⚠️ *战区架构已重组,请务必点击下方指令并发送,以同步新的防撞档案:*
|
||||
\`${REG_MSG}\`" >/dev/null 2>&1
|
||||
echo -e "\033[32m✅ 升级通知已推送!请前往 TG 点击注册指令完成身份同步!\033[0m"
|
||||
|
||||
# [路由表 2]: 现代静默升级 (老版本 >= v3.3.2)
|
||||
else
|
||||
echo -e "\n📡 [路由枢纽] 正在执行静默平滑升级 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
||||
curl -s -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
-d "parse_mode=Markdown" \
|
||||
-d "text=✨ *IP-Sentinel 引擎热更新完成!*
|
||||
📍 节点:\`${NODE_NAME}\`
|
||||
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
||||
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署" >/dev/null 2>&1
|
||||
echo -e "\033[32m✅ 升级成功通知已推送到您的 Telegram!\033[0m"
|
||||
fi
|
||||
|
||||
# [清理遗留垃圾并刷新版本号]
|
||||
sed -i '/^NAME_HASHED=/d' "$CONFIG_FILE" 2>/dev/null # 抹除上个版本的临时基因锁
|
||||
if grep -q "^AGENT_VERSION=" "$CONFIG_FILE"; then
|
||||
sed -i "s/^AGENT_VERSION=.*/AGENT_VERSION=\"$TARGET_VERSION\"/" "$CONFIG_FILE"
|
||||
else
|
||||
echo "AGENT_VERSION=\"$TARGET_VERSION\"" >> "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
else
|
||||
# [全新安装路由]
|
||||
echo -e "\n📡 正在向指挥部发送注册暗号..."
|
||||
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
-d "parse_mode=Markdown" \
|
||||
-d "text=✨ *IP-Sentinel 部署成功!*
|
||||
📍 区域:${REGION_NAME}
|
||||
🌐 IP:${BIND_IP}
|
||||
🌐 IP:${SAFE_PUBLIC_IP}
|
||||
🔌 端口:${AGENT_PORT}
|
||||
|
||||
🔑 *请点击下方指令复制并回复给机器人:*
|
||||
@@ -486,8 +593,8 @@ if [[ -n "$TG_TOKEN" ]]; then
|
||||
elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld | grep -qw active; then
|
||||
FW_MSG="firewall-cmd --zone=public --add-port=$AGENT_PORT/tcp --permanent && firewall-cmd --reload"
|
||||
elif command -v iptables >/dev/null 2>&1; then
|
||||
# 智能双栈雷达:根据绑定的 IP 属性,动态下发对应的防火墙放行指令
|
||||
if [[ "$BIND_IP" == *":"* ]]; then
|
||||
# 智能双栈雷达:根据对外公网 IP 属性,动态下发对应的防火墙放行指令
|
||||
if [[ "$SAFE_PUBLIC_IP" == *":"* ]]; then
|
||||
FW_MSG="ip6tables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT"
|
||||
else
|
||||
FW_MSG="iptables -I INPUT -p tcp --dport $AGENT_PORT -j ACCEPT"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: mod_google.sh (Google 业务逻辑模块)
|
||||
# 脚本名称: mod_google.sh (Google 业务逻辑模块 v3.4.0 版本锚点版)
|
||||
# 核心功能: 执行坐标微抖动、模拟真实阅读时长、会话行为拉伸
|
||||
# ==========================================================
|
||||
|
||||
@@ -16,11 +16,15 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 容错机制:如果父进程没有传递 log 函数,则本地定义一个作为 fallback
|
||||
# 容错机制:如果父进程没有传递 log 函数,则本地定义一个作为 fallback (v3.4.0 引入版本探针)
|
||||
if ! type log >/dev/null 2>&1; then
|
||||
log() {
|
||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||
local local_ver="${AGENT_VERSION:-未知}"
|
||||
|
||||
mkdir -p "${INSTALL_DIR}/logs"
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [%-5s] [%-7s] [%s] %s\n" "$2" "$1" "$REGION_CODE" "$3" >> "${INSTALL_DIR}/logs/sentinel.log"
|
||||
# 统一日志格式,注入 [版本号] 追踪标识
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [v%-5s] [%-5s] [%-7s] [%s] %s\n" "$local_ver" "$2" "$1" "$REGION_CODE" "$3" >> "${INSTALL_DIR}/logs/sentinel.log"
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -48,8 +52,8 @@ get_random_coord() {
|
||||
}
|
||||
|
||||
# --- [环境初始化] ---
|
||||
# [v3.0.2修复] 直接读取系统已锁定的锚点 IP,彻底杜绝“获取IP失败”及隧道偏移
|
||||
CURRENT_IP="${BIND_IP:-Unknown}"
|
||||
# [v3.3.1修改] 优先读取对外公网面孔作为哈希种子,兼容 NAT 机的空 BIND_IP
|
||||
CURRENT_IP="${PUBLIC_IP:-${BIND_IP:-Unknown}}"
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# [V3.1.5] 哈希锚定法 (Hash-Seeded Persona)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: mod_trust.sh (IP 信用净化模块 V3.1.4 拓扑自适应版)
|
||||
# 脚本名称: mod_trust.sh (IP 信用净化模块 v3.4.0 版本锚点版)
|
||||
# 核心功能: 动态扫描本地 LBS 冷数据,提取权威白名单,执行流量净化
|
||||
# ==========================================================
|
||||
|
||||
@@ -41,12 +41,16 @@ if [ ${#TRUST_URLS[@]} -eq 0 ]; then
|
||||
TRUST_URLS=("https://en.wikipedia.org/wiki/Special:Random" "https://www.apple.com/" "https://www.microsoft.com/")
|
||||
fi
|
||||
|
||||
# 3. 日志规范化
|
||||
# 3. 日志规范化 (v3.4.0 引入版本探针)
|
||||
log_msg() {
|
||||
local TYPE=$1
|
||||
local MSG=$2
|
||||
local TIME=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
echo "[$TIME] [$TYPE] [Trust ] [$REGION] $MSG" | tee -a "$LOG_FILE"
|
||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||
local local_ver="${AGENT_VERSION:-未知}"
|
||||
|
||||
# 日志格式注入 [版本号] 追踪标识,保持对齐
|
||||
echo "[$TIME] [v%-5s] [%-5s] [Trust ] [$REGION] $MSG" | sed "s/%-5s/$local_ver/;s/%-5s/$TYPE/" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
# 4. 锁定单次会话指纹
|
||||
@@ -59,8 +63,8 @@ if [ -f "$UA_FILE" ]; then
|
||||
TOTAL_UA=${#UA_POOL[@]}
|
||||
|
||||
if [ "$TOTAL_UA" -gt 0 ]; then
|
||||
# 以本地锁定的公网 IP (BIND_IP) 为种子计算 CRC32 哈希值
|
||||
SEED=$(echo -n "${BIND_IP:-127.0.0.1}" | cksum | awk '{print $1}')
|
||||
# [v3.3.1修改] 优先使用固化的公网 IP 作为哈希种子,防止 NAT 节点指纹同质化
|
||||
SEED=$(echo -n "${PUBLIC_IP:-${BIND_IP:-127.0.0.1}}" | cksum | awk '{print $1}')
|
||||
|
||||
# 利用确定的种子,在全球 4000 的库中,计算出本机的 3 个绝对专属坐标
|
||||
IDX1=$(( SEED % TOTAL_UA ))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: runner.sh (IP-Sentinel 主控调度引擎 V2.0 智能分配版)
|
||||
# 脚本名称: runner.sh (IP-Sentinel 主控调度引擎 v3.4.0 版本锚点版)
|
||||
# 核心功能: 防并发延迟启动、功能开关(Feature Flag)自适应、多模块概率轮盘调度
|
||||
# ==========================================================
|
||||
|
||||
@@ -15,14 +15,18 @@ if [ ! -f "$CONFIG_FILE" ]; then
|
||||
fi
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# 2. 全局日志写入函数 (导出给子进程共享使用)
|
||||
# 2. 全局日志写入函数 (导出给子进程共享使用,v3.4.0 引入版本探针)
|
||||
log() {
|
||||
local module=$1
|
||||
local level=$2
|
||||
local msg=$3
|
||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||
local local_ver="${AGENT_VERSION:-未知}"
|
||||
|
||||
# 保证日志目录存在
|
||||
mkdir -p "${INSTALL_DIR}/logs"
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [%-5s] [%-7s] [%s] %s\n" "$level" "$module" "$REGION_CODE" "$msg" >> "$LOG_FILE"
|
||||
# 日志格式注入 [版本号] 追踪标识
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [v%-5s] [%-5s] [%-7s] [%s] %s\n" "$local_ver" "$level" "$module" "$REGION_CODE" "$msg" >> "$LOG_FILE"
|
||||
}
|
||||
export -f log
|
||||
export CONFIG_FILE INSTALL_DIR
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: tg_report.sh (Telegram 每日战报模块 V6.0 动态拼装版)
|
||||
# 脚本名称: tg_report.sh (Telegram 每日战报模块 V3.4.0 动态拼装版)
|
||||
# 核心功能: 适配 Feature Flag 架构,按需展示 Google/Trust 独立统计数据
|
||||
# ==========================================================
|
||||
|
||||
@@ -19,7 +19,9 @@ if [ -z "$TG_TOKEN" ] || [ -z "$CHAT_ID" ]; then
|
||||
fi
|
||||
|
||||
# 2. 节点元数据抓取 (v3.2.2 协议自适应与多级容灾版)
|
||||
NODE_NAME=$(hostname | cut -c 1-15)
|
||||
# [v3.3.2 修复: 引入 IP 哈希防同名覆盖机制]
|
||||
IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||
NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}"
|
||||
|
||||
# --- [防线 1: 底层路由锁定与协议自适应] ---
|
||||
CURL_BIND_OPT=""
|
||||
@@ -36,8 +38,8 @@ fi
|
||||
|
||||
# 多节点容灾探测出口 IP (注入协议自适应)
|
||||
CURRENT_IP=$( (curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 api.ip.sb/ip || curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -s -m 5 ifconfig.me) 2>/dev/null | tr -d '[:space:]' )
|
||||
# 强制兜底:如果所有外部 API 都挂了,直接使用本地强行锁定的 BIND_IP
|
||||
[ -z "$CURRENT_IP" ] && CURRENT_IP="$BIND_IP"
|
||||
# [v3.3.1 修改] 强制兜底:如果外部 API 挂了,优先使用固化的对外公网面孔 (兼容 NAT 机的空 BIND_IP)
|
||||
[ -z "$CURRENT_IP" ] && CURRENT_IP="${PUBLIC_IP:-$BIND_IP}"
|
||||
|
||||
# 为可能获取到的 IPv6 自动添加方括号护甲
|
||||
[[ "$CURRENT_IP" == *":"* ]] && [[ "$CURRENT_IP" != *"["* ]] && CURRENT_IP="[${CURRENT_IP}]"
|
||||
@@ -153,12 +155,41 @@ else
|
||||
|
||||
🕒 **最近执行快照 [${LAST_MOD:-"System"}]:**
|
||||
时间: ${LAST_TIME:-"暂无数据"}
|
||||
结论: ${LAST_SCORE:-"暂无数据"}
|
||||
----------------------------
|
||||
💡 哨兵正在后台默默守护您的资产。"
|
||||
结论: ${LAST_SCORE:-"暂无数据"}"
|
||||
|
||||
fi
|
||||
|
||||
# ==========================================
|
||||
# 5. [v3.4.0 新增] 云端版本探针与告警模块
|
||||
# ==========================================
|
||||
# 从配置文件提取当前本地版本,若无则默认为未知
|
||||
LOCAL_VER="${AGENT_VERSION:-未知}"
|
||||
|
||||
# 极轻量级探针: 抓取 GitHub 云端的 version.txt (超时 3 秒)
|
||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||
REMOTE_VER=$(curl -s -m 3 "${REPO_RAW_URL}/version.txt" | tr -d '[:space:]')
|
||||
|
||||
# 构建底部引擎状态块
|
||||
MSG="$MSG
|
||||
----------------------------
|
||||
🛡️ **系统引擎状态**
|
||||
当前运行版本: \`v${LOCAL_VER}\`"
|
||||
|
||||
# 比对逻辑:如果成功抓到了远端版本,且和本地不一样
|
||||
if [ -n "$REMOTE_VER" ] && [ "$REMOTE_VER" != "$LOCAL_VER" ]; then
|
||||
MSG="$MSG
|
||||
最新官方版本: \`v${REMOTE_VER}\` (✨有新版)
|
||||
💡 *司令部提示:检测到新版装甲,请长官登录节点执行平滑热更新!*"
|
||||
elif [ -n "$REMOTE_VER" ] && [ "$REMOTE_VER" == "$LOCAL_VER" ]; then
|
||||
MSG="$MSG
|
||||
最新官方版本: \`v${REMOTE_VER}\` (✅已是最新)
|
||||
💡 *哨兵正在后台默默守护您的资产。*"
|
||||
else
|
||||
# 抓取失败兜底
|
||||
MSG="$MSG
|
||||
💡 *哨兵正在后台默默守护您的资产。*"
|
||||
fi
|
||||
|
||||
# 5. 调用 API 推送 (接入安全网关)
|
||||
RESPONSE=$(curl -s -m 10 -X POST "${TG_API_URL}" \
|
||||
-d "chat_id=${CHAT_ID}" \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: uninstall.sh (IP-Sentinel 一键卸载脚本 V3.1.4 焦土版)
|
||||
# 脚本名称: uninstall.sh (IP-Sentinel 一键卸载脚本 V3.4.0 焦土版)
|
||||
# 核心功能: 无痕清理守护进程、定时任务、运行目录及临时缓存
|
||||
# ==========================================================
|
||||
|
||||
@@ -9,6 +9,13 @@ INSTALL_DIR="/opt/ip_sentinel"
|
||||
|
||||
echo "========================================================"
|
||||
echo " 🗑️ 准备卸载 IP-Sentinel (边缘节点 Edge Agent)"
|
||||
|
||||
# [v3.4.0 优化] 尝试获取当前本地版本号
|
||||
CONFIG_FILE="${INSTALL_DIR}/config.conf"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
CURRENT_VER=$(grep "^AGENT_VERSION=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||
[ -n "$CURRENT_VER" ] && echo " 📍 目标版本: v${CURRENT_VER}"
|
||||
fi
|
||||
echo "========================================================"
|
||||
|
||||
# 1. 停止运行中的守护进程与主控模块 (涵盖所有历史版本进程)
|
||||
@@ -17,6 +24,8 @@ echo "[1/3] 正在终止后台守护进程与所有养护任务..."
|
||||
# 使用 pkill 替代传统的 pgrep | xargs,指令更短、容错率更高
|
||||
pkill -9 -f "tg_daemon.sh" >/dev/null 2>&1
|
||||
pkill -9 -f "agent_daemon.sh" >/dev/null 2>&1
|
||||
# [v3.4.0 优化] 确保清理所有 python3 调起的 Webhook 实例
|
||||
pkill -9 -f "python3.*webhook.py" >/dev/null 2>&1
|
||||
pkill -9 -f "webhook.py" >/dev/null 2>&1
|
||||
pkill -9 -f "runner.sh" >/dev/null 2>&1
|
||||
pkill -9 -f "updater.sh" >/dev/null 2>&1
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: updater.sh (IP-Sentinel V3.1.4 养料注入与维护中枢)
|
||||
# 核心功能: 静默更新热数据(指纹/词库/LBS规则)、清理瘦身日志
|
||||
# 脚本名称: updater.sh (IP-Sentinel v3.4.0 养料注入与分频调度中枢)
|
||||
# 核心功能: 静默更新热搜词/LBS、指纹库错峰调度、强制出站死锁、版本锚点版
|
||||
# ==========================================================
|
||||
|
||||
INSTALL_DIR="/opt/ip_sentinel"
|
||||
CONFIG_FILE="${INSTALL_DIR}/config.conf"
|
||||
# 你的 GitHub 仓库 Raw 数据直链前缀 (统一标准)
|
||||
UA_TIME_FILE="${INSTALL_DIR}/core/.ua_last_update"
|
||||
|
||||
# GitHub 仓库 Raw 数据直链前缀
|
||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||
# 临时改为私库地址用于测试
|
||||
# REPO_RAW_URL="https://git.94211762.xyz/hotyue/IP-Sentinel/raw/branch/main"
|
||||
|
||||
# 1. 加载本地冷数据配置
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
@@ -18,57 +18,106 @@ if [ ! -f "$CONFIG_FILE" ]; then
|
||||
fi
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# 2. 全局日志写入函数
|
||||
# 2. 全局日志写入函数 (v3.4.0 引入版本探针)
|
||||
log() {
|
||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||
local local_ver="${AGENT_VERSION:-未知}"
|
||||
|
||||
mkdir -p "${INSTALL_DIR}/logs"
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [%-5s] [%-7s] [%s] %s\n" "$2" "$1" "$REGION_CODE" "$3" >> "$LOG_FILE"
|
||||
# 日志格式注入 [版本号] 追踪标识
|
||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [v%-5s] [%-5s] [%-7s] [%s] %s\n" "$local_ver" "$2" "$1" "$REGION_CODE" "$3" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "Updater" "INFO " "========== 触发后台静默 OTA 热数据更新 =========="
|
||||
|
||||
# 3. 容灾机制拉取 UA 指纹池 (强制遵循锚点协议)
|
||||
TMP_UA="/tmp/ip_sentinel_ua.txt"
|
||||
curl -${IP_PREF:-4} -sL "${REPO_RAW_URL}/data/user_agents.txt" -o "$TMP_UA"
|
||||
if [ -s "$TMP_UA" ]; then
|
||||
mv "$TMP_UA" "${INSTALL_DIR}/data/user_agents.txt"
|
||||
log "Updater" "INFO " "✅ 设备指纹池 (User-Agents) 更新成功"
|
||||
else
|
||||
log "Updater" "WARN " "❌ UA 池拉取失败,保留本地旧数据防崩溃"
|
||||
rm -f "$TMP_UA"
|
||||
# ==========================================================
|
||||
# 🛡️ 终极护城河:构建强锚定出站的 curl 请求引擎
|
||||
# ==========================================================
|
||||
# 基础参数:跟随 install.sh 锁定的协议偏好 (4 或 6)
|
||||
CURL_CMD="curl -${IP_PREF:-4} -sL"
|
||||
|
||||
# 【防坑核心】如果用户配置了死锁锚点,必须强制绑定网卡,杜绝流量溢出!
|
||||
if [ -n "$BIND_IP" ]; then
|
||||
# curl 的 --interface 参数不支持带方括号的 IPv6 地址,必须强行脱壳
|
||||
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||
CURL_CMD="$CURL_CMD --interface $RAW_BIND_IP"
|
||||
fi
|
||||
|
||||
# 4. 容灾机制拉取当地最新搜索词库
|
||||
# ==========================================================
|
||||
# 3. 容灾机制拉取 UA 指纹池 (V3.3.0 引入 30 天错峰防惊群逻辑)
|
||||
# ==========================================================
|
||||
NOW=$(date +%s)
|
||||
LAST_UPDATE=0
|
||||
|
||||
# 读取上一次更新的时间戳
|
||||
if [ -f "$UA_TIME_FILE" ]; then
|
||||
# tr -d 清除可能存在的换行或回车符,防止算术崩溃
|
||||
LAST_UPDATE=$(cat "$UA_TIME_FILE" | tr -d '\r\n')
|
||||
fi
|
||||
|
||||
# 校验数据合法性,防崩溃
|
||||
if ! [[ "$LAST_UPDATE" =~ ^[0-9]+$ ]]; then
|
||||
LAST_UPDATE=0
|
||||
fi
|
||||
|
||||
DIFF=$((NOW - LAST_UPDATE))
|
||||
|
||||
# 距离上次拉取超过 30 天 (2592000 秒),才执行下载
|
||||
if [ "$DIFF" -ge 2592000 ] || [ "$LAST_UPDATE" -eq 0 ]; then
|
||||
TMP_UA="/tmp/ip_sentinel_ua.txt"
|
||||
# 使用重装升级后的 CURL_CMD
|
||||
$CURL_CMD "${REPO_RAW_URL}/data/user_agents.txt" -o "$TMP_UA"
|
||||
|
||||
if [ -s "$TMP_UA" ]; then
|
||||
mv "$TMP_UA" "${INSTALL_DIR}/data/user_agents.txt"
|
||||
echo "$NOW" > "$UA_TIME_FILE"
|
||||
log "Updater" "INFO " "✅ 设备指纹池 (User-Agents) 30天错峰滚动更新成功"
|
||||
else
|
||||
log "Updater" "WARN " "❌ UA 池拉取失败,保留本地旧数据防崩溃"
|
||||
rm -f "$TMP_UA"
|
||||
fi
|
||||
else
|
||||
DAYS_LEFT=$(((2592000 - DIFF) / 86400))
|
||||
log "Updater" "INFO " "⏳ 设备指纹池处于 30 天静默期 (剩余约 ${DAYS_LEFT} 天),跳过拉取"
|
||||
fi
|
||||
|
||||
# ==========================================================
|
||||
# 4. 容灾机制拉取当地最新搜索词库 (每日高频拉取,保证活体新鲜度)
|
||||
# ==========================================================
|
||||
TMP_KW="/tmp/ip_sentinel_kw.txt"
|
||||
curl -${IP_PREF:-4} -sL "${REPO_RAW_URL}/data/keywords/kw_${REGION_CODE}.txt" -o "$TMP_KW"
|
||||
$CURL_CMD "${REPO_RAW_URL}/data/keywords/kw_${REGION_CODE}.txt" -o "$TMP_KW"
|
||||
|
||||
if [ -s "$TMP_KW" ]; then
|
||||
mv "$TMP_KW" "${INSTALL_DIR}/data/keywords/kw_${REGION_CODE}.txt"
|
||||
log "Updater" "INFO " "✅ 区域搜索词库 (kw_${REGION_CODE}) 更新成功"
|
||||
log "Updater" "INFO " "✅ 区域搜索词库 (kw_${REGION_CODE}) 每日同步成功"
|
||||
else
|
||||
log "Updater" "WARN " "❌ 搜索词库拉取失败,保留本地旧数据防崩溃"
|
||||
rm -f "$TMP_KW"
|
||||
fi
|
||||
|
||||
# 5. 【V3.1.4 核心升级】自适应拉取本地 LBS 专属 JSON 规则库
|
||||
# 利用 find 穿透寻找本地唯一的 json
|
||||
# ==========================================================
|
||||
# 5. 自适应拉取本地 LBS 专属 JSON 规则库 (每日同步)
|
||||
# ==========================================================
|
||||
REGION_JSON_FILE=$(find "${INSTALL_DIR}/data/regions" -name "*.json" 2>/dev/null | head -n 1)
|
||||
|
||||
if [ -n "$REGION_JSON_FILE" ] && [ -f "$REGION_JSON_FILE" ]; then
|
||||
# 提取本地文件的相对路径 (例如: data/regions/US/CA/San_Jose.json)
|
||||
REL_PATH=${REGION_JSON_FILE#*${INSTALL_DIR}/}
|
||||
TMP_JSON="/tmp/ip_sentinel_region.json"
|
||||
|
||||
# 按照相同的相对路径去云端拉取更新
|
||||
curl -${IP_PREF:-4} -sL "${REPO_RAW_URL}/${REL_PATH}" -o "$TMP_JSON"
|
||||
$CURL_CMD "${REPO_RAW_URL}/${REL_PATH}" -o "$TMP_JSON"
|
||||
|
||||
if [ -s "$TMP_JSON" ]; then
|
||||
mv "$TMP_JSON" "$REGION_JSON_FILE"
|
||||
log "Updater" "INFO " "✅ 核心战区规则库 ($REL_PATH) 更新成功"
|
||||
log "Updater" "INFO " "✅ 核心战区规则库 ($REL_PATH) 每日同步成功"
|
||||
else
|
||||
log "Updater" "WARN " "❌ 战区规则库拉取失败,保留本地旧数据"
|
||||
rm -f "$TMP_JSON"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ==========================================================
|
||||
# 6. 日志防满瘦身机制 (保留最近 2000 行)
|
||||
# ==========================================================
|
||||
if [ -f "$LOG_FILE" ]; then
|
||||
tail -n 2000 "$LOG_FILE" > "${LOG_FILE}.tmp"
|
||||
mv "${LOG_FILE}.tmp" "$LOG_FILE"
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
dietrich grönemeyer
|
||||
fränkische schweiz
|
||||
scarlett johansson
|
||||
jeff bezos
|
||||
dan brown
|
||||
паспорт громадянина україни для виїзду за кордон
|
||||
serena williams
|
||||
kampf der realitystars
|
||||
манчестер юнайтед – лидс
|
||||
catherine deneuve
|
||||
bobzin
|
||||
sprit
|
||||
kev
|
||||
abschiebung
|
||||
steuer
|
||||
masters rory mcilroy
|
||||
großglockner
|
||||
news38
|
||||
jessie cave
|
||||
michael schulte
|
||||
wetter frankfurt heute
|
||||
bundesliga ergebnisse
|
||||
aktuelle nachrichten deutschland
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
yann barthes
|
||||
camille cerf
|
||||
alain delon
|
||||
loto du 13 avril 2026
|
||||
juan arbeláez
|
||||
hbo
|
||||
katy perry justin trudeau
|
||||
jacob elordi
|
||||
tondela – gil vicente
|
||||
le rugbynistère
|
||||
epstein
|
||||
kino
|
||||
horoscope du 13 avril 2026
|
||||
golf masters augusta 2026
|
||||
boursorama bourse
|
||||
cac 40
|
||||
sept à huit
|
||||
ligne 12 métro
|
||||
alice taglioni
|
||||
pedro sánchez
|
||||
meteo paris
|
||||
actualités en direct
|
||||
résultats ligue 1
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
man united vs leeds
|
||||
曼聯 對 里茲聯
|
||||
prediction market
|
||||
預測市場
|
||||
polymarket
|
||||
巴基斯坦
|
||||
sndk
|
||||
江美儀
|
||||
楊何蓓茵
|
||||
樂珈嘉
|
||||
姜濤
|
||||
日經平均指數
|
||||
飲茶
|
||||
上市公司
|
||||
daniel caesar
|
||||
中年好聲音4
|
||||
香港天文台
|
||||
煤氣
|
||||
livenation
|
||||
政府
|
||||
香港天文台天氣預報
|
||||
MTR 港鐵路線圖
|
||||
OpenRice 附近美食
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
man united vs leeds
|
||||
白鵬翔
|
||||
日本アカデミー賞 最優秀助演男優賞
|
||||
マンu 対 リーズ u
|
||||
サンディスク 株価
|
||||
らじるらじる
|
||||
マクドナルド
|
||||
ロシア
|
||||
広島市
|
||||
ゲイブル・スティーブソン
|
||||
日本維新の会
|
||||
新 日本 繊維
|
||||
高見沢 俊彦
|
||||
不登校
|
||||
後期高齢者医療制度
|
||||
バーミヤン
|
||||
宮澤エマ
|
||||
チケプラ
|
||||
横綱
|
||||
宮里美香
|
||||
東京 天気 明日
|
||||
新宿 おすすめ 居酒屋
|
||||
最新のニュース 速報
|
||||
ゴールド 相場 チャート
|
||||
近くの静かなカフェ
|
||||
地震 速報
|
||||
円安 影響 生活
|
||||
円安 影響 生活
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
man united vs leeds
|
||||
cbse class 10 result 2026 date
|
||||
euphoria season 3
|
||||
srh vs rr
|
||||
tamil new year 2026
|
||||
low de wei
|
||||
pope
|
||||
flexar
|
||||
microsoft outlook
|
||||
new rolex 2026
|
||||
medical classification
|
||||
blasphemy law
|
||||
big bang coachella 2026
|
||||
小贩
|
||||
malaysia fuel price crisis
|
||||
sbti personality test
|
||||
cancer survivor
|
||||
tim cook
|
||||
spurs vs nuggets
|
||||
asia flights cancelled delayed
|
||||
singapore weather forecast
|
||||
mrt map singapore
|
||||
straitstimes breaking news
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
noah okafor
|
||||
casemiro
|
||||
talksport
|
||||
lazio
|
||||
leeds united fixtures
|
||||
bruno fernandes
|
||||
afc champions league
|
||||
meteor
|
||||
carlos queiroz
|
||||
travel warning
|
||||
tori amos
|
||||
cloud
|
||||
reading
|
||||
rolls-royce smr
|
||||
istanbul airport
|
||||
a27
|
||||
bridget phillipson
|
||||
tottenham standings
|
||||
may bank holiday 2026
|
||||
toto wolff
|
||||
london weather today
|
||||
bbc news latest
|
||||
premier league fixtures
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
usa network
|
||||
natalie sago
|
||||
carlos queiroz
|
||||
carlos batista
|
||||
katie boulter
|
||||
levante - getafe
|
||||
levante vs getafe
|
||||
mcilroy green jacket presentation
|
||||
man united vs leeds
|
||||
7-eleven closing locations
|
||||
cloud
|
||||
sports
|
||||
sony playstation
|
||||
alaska airline
|
||||
toronto
|
||||
sydney
|
||||
paris
|
||||
tokyo
|
||||
delhi
|
||||
sykkuno drama
|
||||
Los Angeles weather today
|
||||
S&P 500 stock chart
|
||||
local coffee shops near me
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: install_master.sh (IP-Sentinel 控制中枢部署脚本 v3.2.3)
|
||||
# 脚本名称: install_master.sh (IP-Sentinel 控制中枢部署脚本 v3.4.0)
|
||||
# 核心功能: 部署/卸载调度中枢、SQLite 资产管理、平滑热更新引擎
|
||||
# ==========================================================
|
||||
|
||||
# [新增] 提取仓库直链前缀变量,方便后续在官方库和私库间一键切换
|
||||
# [v3.4.0 核心: 全局版本控制锚点]
|
||||
TARGET_VERSION="3.4.0"
|
||||
|
||||
# 你的 GitHub 仓库 Raw 数据直链前缀
|
||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||
# 临时改为私库地址用于测试
|
||||
# REPO_RAW_URL="https://git.94211762.xyz/hotyue/IP-Sentinel/raw/branch/main"
|
||||
@@ -15,7 +18,7 @@ DB_FILE="${MASTER_DIR}/sentinel.db"
|
||||
|
||||
echo "========================================================"
|
||||
# [修改] 将欢迎语改为更通用的文案,因为现在不仅能部署,还能卸载
|
||||
echo " 🧠 欢迎使用 IP-Sentinel Master (控制中枢) v3.2.2"
|
||||
echo " 🧠 欢迎使用 IP-Sentinel Master (控制中枢) v${TARGET_VERSION}"
|
||||
echo "========================================================"
|
||||
|
||||
# [新增] 交互式操作菜单:支持选择部署或调用卸载程序
|
||||
@@ -50,7 +53,15 @@ if [ "$ACTION_CHOICE" == "1" ] && [ -f "${MASTER_DIR}/master.conf" ]; then
|
||||
|
||||
# 汲取原配置进入内存
|
||||
source "${MASTER_DIR}/master.conf"
|
||||
echo -e "\033[32m✅ 已激活 [平滑升级模式],即将跳过基础配置,直接更新核心中枢...\033[0m"
|
||||
|
||||
# [v3.4.0 核心] 升级后立即同步/补录版本号至配置文件
|
||||
if grep -q "^MASTER_VERSION=" "${MASTER_DIR}/master.conf"; then
|
||||
sed -i "s/^MASTER_VERSION=.*/MASTER_VERSION=\"$TARGET_VERSION\"/" "${MASTER_DIR}/master.conf"
|
||||
else
|
||||
echo "MASTER_VERSION=\"$TARGET_VERSION\"" >> "${MASTER_DIR}/master.conf"
|
||||
fi
|
||||
|
||||
echo -e "\033[32m✅ 已激活 [平滑升级模式],版本已锚定为 v${TARGET_VERSION}...\033[0m"
|
||||
else
|
||||
echo -e "\033[33m🔄 您选择了重新配置,旧的中枢数据将被彻底抹除。\033[0m"
|
||||
fi
|
||||
@@ -97,6 +108,8 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
||||
read -p "请输入 Telegram Bot Token: " TG_TOKEN
|
||||
|
||||
cat > "${MASTER_DIR}/master.conf" << EOF
|
||||
# IP-Sentinel Master 本地固化配置 (v3.4.0)
|
||||
MASTER_VERSION="$TARGET_VERSION"
|
||||
TG_TOKEN="$TG_TOKEN"
|
||||
DB_FILE="$DB_FILE"
|
||||
MASTER_DIR="$MASTER_DIR"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: tg_master.sh (Master 端调度枢纽 V3.0.4 动态签名版)
|
||||
# 脚本名称: tg_master.sh (Master 端调度枢纽 V3.3.2 动态签名版)
|
||||
# 核心功能: 监听 TG、操作 SQLite、Webhook 精准调度、403权限拦截、僵尸节点清理
|
||||
# ==========================================================
|
||||
|
||||
@@ -9,6 +9,10 @@ CONF="/opt/ip_sentinel_master/master.conf"
|
||||
[ ! -f "$CONF" ] && exit 1
|
||||
source "$CONF"
|
||||
|
||||
# [v3.4.0 核心: 主控版本锚点与云通信地址]
|
||||
MASTER_VERSION="3.4.0"
|
||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||
|
||||
OFFSET_FILE="${MASTER_DIR}/.tg_offset"
|
||||
[[ -f $OFFSET_FILE ]] || echo "0" > $OFFSET_FILE
|
||||
|
||||
@@ -117,7 +121,7 @@ while true; do
|
||||
|
||||
# 入库时追加 region 字段
|
||||
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION';"
|
||||
send_msg "$CHAT_ID" "✅ 司令部已确认!节点接入成功: \`$NODE_NAME\` ($AGENT_IP:$AGENT_PORT)"
|
||||
send_msg "$CHAT_ID" "✅ **司令部确认 (v${MASTER_VERSION})**\n节点接入成功: \`$NODE_NAME\`\n地址: \`$AGENT_IP:$AGENT_PORT\`"
|
||||
|
||||
# ================== [v3.1.3 丝滑连招: 直接呼出全球大区雷达] ==================
|
||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||
@@ -129,6 +133,7 @@ while true; do
|
||||
case "$REGION_NAME" in
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
"CA") FLAG="🇨🇦" ;; "AU") FLAG="🇦🇺" ;; "KR") FLAG="🇰🇷" ;; "NL") FLAG="🇳🇱" ;; "BR") FLAG="🇧🇷" ;; "IN") FLAG="🇮🇳" ;; "TW") FLAG="🇹🇼" ;;
|
||||
esac
|
||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||
done <<< "$REGION_DATA"
|
||||
@@ -145,8 +150,16 @@ while true; do
|
||||
# ==========================================
|
||||
case "$TEXT" in
|
||||
"/start"|"/menu")
|
||||
# [v3.4.0 核心] 抓取云端最新版本
|
||||
REMOTE_VER=$(curl -s -m 2 "${REPO_RAW_URL}/version.txt" | tr -d '[:space:]')
|
||||
VER_INFO="当前版本: \`v${MASTER_VERSION}\`"
|
||||
|
||||
if [ -n "$REMOTE_VER" ] && [ "$REMOTE_VER" != "$MASTER_VERSION" ]; then
|
||||
VER_INFO="${VER_INFO}\n✨ **发现新版本**: \`v${REMOTE_VER}\` (请尽快更新主控)"
|
||||
fi
|
||||
|
||||
BTNS="[[{\"text\":\"🖥️ 我的节点列表\",\"callback_data\":\"list_nodes\"}], [{\"text\":\"🚀 全节点日报汇总\",\"callback_data\":\"all_reports\"}], [{\"text\":\"🛠️ 全节点一键维护\",\"callback_data\":\"all_run\"}]]"
|
||||
send_ui "$CHAT_ID" "🛡️ **IP-Sentinel 司令部**\n欢迎回来,长官。请下达指令:" "$BTNS"
|
||||
send_ui "$CHAT_ID" "🛡️ **IP-Sentinel 司令部**\n${VER_INFO}\n\n欢迎回来,长官。请下达指令:" "$BTNS"
|
||||
;;
|
||||
|
||||
"all_reports")
|
||||
@@ -190,8 +203,9 @@ while true; do
|
||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||
FLAG="🌐"
|
||||
case "$REGION_NAME" in
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
||||
"CA") FLAG="🇨🇦" ;; "AU") FLAG="🇦🇺" ;; "KR") FLAG="🇰🇷" ;; "NL") FLAG="🇳🇱" ;; "BR") FLAG="🇧🇷" ;; "IN") FLAG="🇮🇳" ;; "TW") FLAG="🇹🇼" ;;
|
||||
esac
|
||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||
done <<< "$REGION_DATA"
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ==========================================================
|
||||
# 脚本名称: uninstall_master.sh (IP-Sentinel Master 一键卸载脚本)
|
||||
# 脚本名称: uninstall_master.sh (IP-Sentinel Master 一键卸载脚本 v3.4.0)
|
||||
# 核心功能: 终止调度进程、清理看门狗定时任务、抹除数据库与配置
|
||||
# ==========================================================
|
||||
|
||||
MASTER_DIR="/opt/ip_sentinel_master"
|
||||
CONF_FILE="${MASTER_DIR}/master.conf"
|
||||
|
||||
echo "========================================================"
|
||||
echo " 🗑️ 准备卸载 IP-Sentinel Master (控制中枢)"
|
||||
|
||||
# [v3.4.0 优化] 卸载前读取并播报中枢版本号
|
||||
if [ -f "$CONF_FILE" ]; then
|
||||
MASTER_VER=$(grep "^MASTER_VERSION=" "$CONF_FILE" | cut -d'"' -f2)
|
||||
[ -n "$MASTER_VER" ] && echo " 📍 目标版本: v${MASTER_VER}"
|
||||
fi
|
||||
echo "========================================================"
|
||||
|
||||
echo -e "\n⚠️ 警告: 此操作将永久删除包含所有节点档案的 SQLite 数据库!"
|
||||
|
||||
81
scripts/fetch_trends.py
Normal file
81
scripts/fetch_trends.py
Normal file
@@ -0,0 +1,81 @@
|
||||
import urllib.request
|
||||
import xml.etree.ElementTree as ET
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
|
||||
# ================== [路径防弹装甲] ==================
|
||||
# 无论在哪里执行该脚本,都能精准反推项目根目录
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
PROJECT_ROOT = os.path.dirname(SCRIPT_DIR)
|
||||
|
||||
MAP_JSON_PATH = os.path.join(PROJECT_ROOT, "data", "map.json")
|
||||
DATA_DIR = os.path.join(PROJECT_ROOT, "data", "keywords")
|
||||
# ====================================================
|
||||
|
||||
# 特殊战区代码映射 (Google Trends RSS 要求)
|
||||
GEO_FIX = {'UK': 'GB'}
|
||||
|
||||
HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
||||
}
|
||||
|
||||
def get_active_regions():
|
||||
"""动态提取 map.json 中的战区 (修正:精准穿透 JSON 数组结构)"""
|
||||
try:
|
||||
with open(MAP_JSON_PATH, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
# 穿透到 countries 列表,提取所有的国家代码 (id)
|
||||
regions = []
|
||||
for country in data.get('countries', []):
|
||||
if 'id' in country:
|
||||
regions.append(country['id'])
|
||||
return regions
|
||||
except Exception as e:
|
||||
print(f"❌ [读取地图失败]: {e}")
|
||||
return []
|
||||
|
||||
def fetch_trends(region_code):
|
||||
"""从 Google Trends 抓取当日热搜"""
|
||||
geo = GEO_FIX.get(region_code, region_code)
|
||||
url = f"https://trends.google.com/trending/rss?geo={geo}"
|
||||
try:
|
||||
req = urllib.request.Request(url, headers=HEADERS)
|
||||
with urllib.request.urlopen(req, timeout=10) as response:
|
||||
xml_data = response.read()
|
||||
root = ET.fromstring(xml_data)
|
||||
return [re.sub(r'[\n\r\t]', ' ', item.find('title').text).strip()
|
||||
for item in root.findall('./channel/item')
|
||||
if item.find('title') is not None]
|
||||
except Exception as e:
|
||||
print(f"⚠️ {region_code} 抓取异常: {e}")
|
||||
return []
|
||||
|
||||
def update_file(region, new_words):
|
||||
"""滑动窗口更新,保留 200 条最热记录"""
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
file_path = os.path.join(DATA_DIR, f"kw_{region}.txt")
|
||||
old_words = []
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
old_words = [l.strip() for l in f if l.strip()]
|
||||
|
||||
# 新词排在最前面,去重
|
||||
combined = new_words + [w for w in old_words if w not in new_words]
|
||||
final_list = combined[:200]
|
||||
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
f.write('\n'.join(final_list) + '\n')
|
||||
print(f"✅ [同步完成] {region}: 注入 {len(new_words)} 条新热点")
|
||||
|
||||
if __name__ == '__main__':
|
||||
regions = get_active_regions()
|
||||
if not regions:
|
||||
print("🛑 未发现活跃战区,请检查 map.json")
|
||||
exit(1)
|
||||
|
||||
for r in regions:
|
||||
print(f"📡 正在拉取 {r} 战区情报...")
|
||||
words = fetch_trends(r)
|
||||
if words:
|
||||
update_file(r, words)
|
||||
1
version.txt
Normal file
1
version.txt
Normal file
@@ -0,0 +1 @@
|
||||
3.4.0
|
||||
Reference in New Issue
Block a user