mirror of
https://github.com/hotyue/IP-Sentinel.git
synced 2026-05-11 23:59:42 +08:00
Compare commits
269 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae67817eb4 | ||
|
|
27e48defb2 | ||
|
|
cc216e288e | ||
|
|
9f32bc990d | ||
|
|
3a981f24e3 | ||
|
|
a626283b54 | ||
|
|
12eaf89f48 | ||
|
|
5e1331bad0 | ||
|
|
e44418d381 | ||
|
|
c86f1e509b | ||
|
|
f7f2421843 | ||
|
|
014486e558 | ||
|
|
ce4a40d860 | ||
|
|
36847aeaa2 | ||
|
|
43adf55a4b | ||
|
|
838dc01ebc | ||
|
|
641055ab74 | ||
|
|
5c19b6a6e1 | ||
|
|
af2570f15d | ||
|
|
df77f397aa | ||
|
|
d6dee813c5 | ||
|
|
d20f576908 | ||
|
|
17dd927719 | ||
|
|
bff49cd2b9 | ||
|
|
49090f1b97 | ||
|
|
15324d0840 | ||
|
|
8b632fe4f9 | ||
|
|
11ff23bf94 | ||
|
|
332765a72e | ||
|
|
38869e8681 | ||
|
|
85cd1dc594 | ||
|
|
55f7ee0c8c | ||
|
|
d24be4da0b | ||
|
|
ae36155545 | ||
|
|
dc5560f8fd | ||
|
|
18985cb57d | ||
|
|
830d62ead8 | ||
|
|
5c8d9d6096 | ||
|
|
22d26079e4 | ||
|
|
c564ea0ab8 | ||
|
|
ec7bf0f2b9 | ||
|
|
be241ab6bd | ||
|
|
4b2985b4ef | ||
|
|
d4afb57f9f | ||
|
|
230a59bbb3 | ||
|
|
f4a5cf8306 | ||
|
|
b606fe02ff | ||
|
|
3375356143 | ||
|
|
d9255ecbca | ||
|
|
6ad6f6b4b3 | ||
|
|
a8caea3b6d | ||
|
|
1a49e18200 | ||
|
|
c223d7a476 | ||
|
|
eaa51358a8 | ||
|
|
00827b3b15 | ||
|
|
ccddaf4386 | ||
|
|
0f0ba46989 | ||
|
|
f83db38a6b | ||
|
|
ba5582ab4c | ||
|
|
fb4e1d9b31 | ||
|
|
2dea6e382b | ||
|
|
fa8eada97b | ||
|
|
c102f66234 | ||
|
|
68a50fdb4a | ||
|
|
aac83acb8f | ||
|
|
4be4d5e9ef | ||
|
|
1f925b307f | ||
|
|
49afe032d6 | ||
|
|
f0f054c8cd | ||
|
|
699e9ca31a | ||
|
|
76cace4ff6 | ||
|
|
9f3218ab7f | ||
|
|
8a61f518f5 | ||
|
|
e9d5023263 | ||
|
|
05b1e21bba | ||
|
|
4a496fdab3 | ||
|
|
8ae3a6534d | ||
|
|
3269376c94 | ||
|
|
7a92de4d62 | ||
|
|
5fbc1e3fb3 | ||
|
|
d73c3154f9 | ||
|
|
b3fbed4a94 | ||
|
|
71fe3bde51 | ||
|
|
c739f58cc5 | ||
|
|
2c50c72fcb | ||
|
|
8d16c549fc | ||
|
|
d74d6d8775 | ||
|
|
853e6c09e1 | ||
|
|
1f21ac9a7e | ||
|
|
28fd94eff5 | ||
|
|
7460935acc | ||
|
|
109ae6f319 | ||
|
|
6b3acf5787 | ||
|
|
b1ecbd4f9a | ||
|
|
4d091e4dd9 | ||
|
|
ae6559c850 | ||
|
|
5cfaebceab | ||
|
|
88f55cbab9 | ||
|
|
1204336612 | ||
|
|
49a65a5f11 | ||
|
|
7e5b836a49 | ||
|
|
18f80400ef | ||
|
|
eca4b41da4 | ||
|
|
a24a533165 | ||
|
|
d2b575fe85 | ||
|
|
cb0aa2049e | ||
|
|
981b9e4859 | ||
|
|
eeee1b6811 | ||
|
|
e6852d0c9d | ||
|
|
23ea08f981 | ||
|
|
580a3d7fd5 | ||
|
|
6eabb60c28 | ||
|
|
7fd432ffee | ||
|
|
351143e59d | ||
|
|
725e8ae8c9 | ||
|
|
1e9de46fc5 | ||
|
|
543ab5c8bd | ||
|
|
972cd02874 | ||
|
|
9c37cb9df3 | ||
|
|
2a8a6b6fa7 | ||
|
|
e4b4c747eb | ||
|
|
eabd33e6b2 | ||
|
|
233af7181f | ||
|
|
62fb19f0c5 | ||
|
|
54178ddcf1 | ||
|
|
92a65d8308 | ||
|
|
eaaa7dabf0 | ||
|
|
e797c8203f | ||
|
|
9ecf50c153 | ||
|
|
c02b7eecc9 | ||
|
|
6af8b6b25d | ||
|
|
7081aa77cc | ||
|
|
5e48edb030 | ||
|
|
5f0f677f59 | ||
|
|
7f0c3e3e29 | ||
|
|
c03f6ca9ba | ||
|
|
66f3ba7d06 | ||
|
|
511ba90378 | ||
|
|
01806d20dd | ||
|
|
049278c458 | ||
|
|
0aaa2d44a0 | ||
|
|
3f139a593e | ||
|
|
bee6fef69c | ||
|
|
f283a8a4c6 | ||
|
|
0d2433d850 | ||
|
|
a6b01bd8d5 | ||
|
|
8f2279b7e2 | ||
|
|
d37d26708d | ||
|
|
6234d7c49a | ||
|
|
f9a7bba32a | ||
|
|
068734da16 | ||
|
|
09a4108bcc | ||
|
|
a7f08ec7a7 | ||
|
|
f075fcce36 | ||
|
|
0bb96169e5 | ||
|
|
34320b2385 | ||
|
|
aeed9f0e57 | ||
|
|
c04a4c41e4 | ||
|
|
3b28ead0e4 | ||
|
|
d0ea5d09b1 | ||
|
|
a119973ec0 | ||
|
|
b8b91ac17e | ||
|
|
34f2c7e123 | ||
|
|
172f1e0209 | ||
|
|
1d5ed5d0cb | ||
|
|
1e150f26f1 | ||
|
|
03e735a44b | ||
|
|
011c1faad4 | ||
|
|
2325a8abdf | ||
|
|
201df489db | ||
|
|
2d680c5fc7 | ||
|
|
e77b7c0319 | ||
|
|
2283da7421 | ||
|
|
4a28f7f395 | ||
|
|
9a38fb62d0 | ||
|
|
fefd5dc60c | ||
|
|
89aa1ead33 | ||
|
|
a5f2fb53ed | ||
|
|
bd26f1011d | ||
|
|
cfaf156e03 | ||
|
|
75cf50ce0c | ||
|
|
e2b6bbc347 | ||
|
|
cd5160d1ea | ||
|
|
040827aa27 | ||
|
|
d00317a645 | ||
|
|
60317b4444 | ||
|
|
a0bb0f30f2 | ||
|
|
cc6f7bf958 | ||
|
|
583e0b00d8 | ||
|
|
c27f2fced9 | ||
|
|
8baa141339 | ||
|
|
2eceb43ac3 | ||
|
|
8ce9eb256b | ||
|
|
bf2cfb7da0 | ||
|
|
5dfaa19cca | ||
|
|
3404666b8e | ||
|
|
b64ab95658 | ||
|
|
f19d165ece | ||
|
|
602919dc18 | ||
|
|
722db9f6d1 | ||
|
|
970867f3c7 | ||
|
|
e22d8d3cd0 | ||
|
|
cfe6dd59c8 | ||
|
|
b46e257545 | ||
|
|
3e9a82a657 | ||
|
|
4cf687f436 | ||
|
|
e88cf4ac5b | ||
|
|
898349d22e | ||
|
|
9ea188cb6d | ||
|
|
03d4c6160a | ||
|
|
cf4433cdd6 | ||
|
|
ae80f25c67 | ||
|
|
5b2c294c61 | ||
|
|
a1595ab0c5 | ||
|
|
0be1e92ac5 | ||
|
|
cf3e5dca2f | ||
|
|
902f612d31 | ||
|
|
45475f14b7 | ||
|
|
30f396aefe | ||
|
|
7cf7117615 | ||
|
|
062305d126 | ||
|
|
f451aea643 | ||
|
|
64342b2846 | ||
|
|
d96b6e769a | ||
|
|
539de62eee | ||
|
|
d514106e65 | ||
|
|
7f9c8a4dea | ||
|
|
31014e571d | ||
|
|
f5aa68a8dc | ||
|
|
63bbbd549e | ||
|
|
5e40ed426b | ||
|
|
aebf3a9e90 | ||
|
|
8a3d7c305b | ||
|
|
2d580eaea2 | ||
|
|
d7ab695372 | ||
|
|
0c250dfd17 | ||
|
|
52b12c7057 | ||
|
|
2166753569 | ||
|
|
46e418dfd0 | ||
|
|
673e0ce3e6 | ||
|
|
6203249782 | ||
|
|
05e708ed21 | ||
|
|
c4faa102cf | ||
|
|
4a1b32278c | ||
|
|
584ead387e | ||
|
|
efdc62ba68 | ||
|
|
67618587e4 | ||
|
|
a2c045a841 | ||
|
|
9b35c87cb4 | ||
|
|
e6c6e66e4b | ||
|
|
f1d36a2148 | ||
|
|
41906d0570 | ||
|
|
dc7d1c0f40 | ||
|
|
9768bed637 | ||
|
|
fa202a0405 | ||
|
|
b8bcd09134 | ||
|
|
ef8dc033cc | ||
|
|
03a54bcca0 | ||
|
|
f4f93d8955 | ||
|
|
07cac792f0 | ||
|
|
50edad9e25 | ||
|
|
69edf12620 | ||
|
|
0b448e2b7e | ||
|
|
d7b95136dd | ||
|
|
80d74111c4 | ||
|
|
223d7c4b56 | ||
|
|
de3b4ca6d3 | ||
|
|
423a765e5f | ||
|
|
ca74c31b96 |
26
.github/workflows/daily_keywords.yml
vendored
26
.github/workflows/daily_keywords.yml
vendored
@@ -1,16 +1,19 @@
|
|||||||
name: Daily Trends Factory
|
name: Daily Data Factory
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
# 每天 UTC 18:00 运行 (北京时间凌晨 02:00)
|
# 每天 UTC 03:00 执行,为各节点全天随机拉取准备好弹药
|
||||||
- cron: '0 18 * * *'
|
- cron: '0 3 * * *'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-trends:
|
update-data:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
@@ -23,15 +26,20 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
|
||||||
- name: Execute Trends Engine
|
- name: Execute Trends Engine (搜索词库)
|
||||||
run: python scripts/fetch_trends.py
|
run: python scripts/fetch_trends.py
|
||||||
|
|
||||||
- name: Commit and Push
|
- name: Execute Trust URL Engine (活体新闻流融合)
|
||||||
|
run: python scripts/fetch_trust_urls.py
|
||||||
|
|
||||||
|
- name: Commit and Push All Data
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name "github-actions[bot]"
|
git config --global user.name "github-actions[bot]"
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
# 一揽子添加搜索词库和地区白名单的变化
|
||||||
git add data/keywords/
|
git add data/keywords/
|
||||||
|
git add data/regions/
|
||||||
|
|
||||||
# 防御机制:如果没有新数据,就静默退出,不产生空提交
|
# 防御机制:如果没有新数据,就静默退出,不产生空提交
|
||||||
if git diff --staged --quiet; then
|
if git diff --staged --quiet; then
|
||||||
@@ -39,6 +47,6 @@ jobs:
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 策略:放弃危险的 amend 强制覆盖,采用带日期的标准安全提交
|
# 策略:将两路数据的更新合并为一个原子提交
|
||||||
git commit -m "chore(data): 🤖 自动机兵:刷新全战区热点词库 [$(date +'%Y-%m-%d')]"
|
git commit -m "chore(data): 🤖 自动机兵:同步全战区热点词库与活体新闻流 [$(date +'%Y-%m-%d')]"
|
||||||
git push origin main
|
git push origin main
|
||||||
|
|||||||
4
.github/workflows/ua_factory.yml
vendored
4
.github/workflows/ua_factory.yml
vendored
@@ -2,8 +2,8 @@ name: Automated Massive UA Factory
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
# 每个月 1 号凌晨 00:00 执行
|
# 每个月 1 号凌晨 04:00 执行
|
||||||
- cron: '0 0 1 * *'
|
- cron: '0 4 1 * *'
|
||||||
workflow_dispatch: # 允许手动点击运行
|
workflow_dispatch: # 允许手动点击运行
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
133
README.md
133
README.md
@@ -10,25 +10,22 @@
|
|||||||
|
|
||||||
专为解决 VPS IP 被 Google 等数据库错误定位到中国大陆/香港(俗称“送中”)等问题而生。IP-Sentinel 已从单机脚本全面跃升为 **Master-Agent 分布式架构**。它像影子一样潜伏在全球各地的服务器后台,通过高度拟真的真实用户行为为你默默积累 IP 权重,并允许你通过 Telegram 随时随地对整个舰队进行毫秒级“点名”与“遥控”。
|
专为解决 VPS IP 被 Google 等数据库错误定位到中国大陆/香港(俗称“送中”)等问题而生。IP-Sentinel 已从单机脚本全面跃升为 **Master-Agent 分布式架构**。它像影子一样潜伏在全球各地的服务器后台,通过高度拟真的真实用户行为为你默默积累 IP 权重,并允许你通过 Telegram 随时随地对整个舰队进行毫秒级“点名”与“遥控”。
|
||||||
|
|
||||||
## ✨ 核心极客特性 (Evolution History)
|
## ✨ 核心极客特性 (Core Architecture)
|
||||||
|
|
||||||
- 🌍 **[v3.5.0] 大洲战区与降维引擎 (Continental Grouping)**:随着全球版图的极速扩张,彻底重构底层地图索引。引入“战区(大洲)-国家-省州-城市”四级降维解析菜单,完美承载未来数十个国家的扩容,终端交互界面永远清爽干练。
|
- 📊 **深海声呐全维探针 (Deep Sea Sonar v4.0.4)**:内嵌强效正则去污的 JSON 提取引擎,无损展现免掩码的真实 IP 情报。聚合 Scamalytics、AbuseIPDB 等五大权威防欺诈库,精准嗅探代理/VPN特征、25端口及流媒体原生解锁状态,并自带 Google “送中”高危预警与污染趋势图谱。
|
||||||
- 🧬 **[v3.5.0] SSOT 动态版本溯源 (Single Source of Truth)**:全系脚本彻底消灭硬编码版本号!引入企业级 DevOps 理念,部署时动态抓取云端信标并固化落盘,常驻进程与日志绝对继承本地基因,实现“改一处,全网同步”的极致架构。
|
- ⚡ **无损高并发引擎 (WAL Concurrency)**:司令部 SQLite 数据库全面激活 `WAL` (Write-Ahead Logging) 模式与毫秒级排队算法。即使对 500 台边缘节点发起全军总攻,也能完美规避 `database is locked` 与 Telegram `429` 拦截。
|
||||||
- 🎯 **[v3.4.0] 版本锚点与路由中枢 (Version-Linked Epoch)**:彻底告别“盲盒式更新”,全系引入全局版本号机制。边缘节点具备“身份自知”能力,安装脚本根据本地版本执行精准的路由跳转,实现新老架构的智能化无损跃迁。
|
- 🪶 **抽脂级极简部署 (Zero-Bloat Native)**:全栈剔除第三方依赖,基于 Python3 原生标准库运行。安装强制注入 `--no-install-recommends` 防捆绑参数。无论是 128MB 内存的极简 NAT,还是 Alpine 游击队容器,均可如丝般顺滑运行。
|
||||||
- 📡 **[v3.4.0] OTA 实时版本探针 (Version-Aware Radar)**:边缘哨兵现已接入云端“北极星”校准。每日战报自动扫描 GitHub 最新发布状态,发现版本落后即刻在 Telegram 战报底部亮起 OTA 预警,消除指挥官与前线的信息差。
|
- 🎛️ **扁平化指挥矩阵 (Flat Command Matrix)**:引入扁平化四级战区降维视图与双轨身份制。深度定制 Inline Keyboard 逃生舱交互,支持原位丝滑重绘 (In-place UI Edit),实现毫秒级模块热启停与跨地域深海声呐投放。
|
||||||
- 📡 **[v3.3.0] OTA 动态活体词库 (Dynamic Trends)**:彻底废弃静态搜索词,引入 GitHub Actions 云端流水线。每天自动抓取全战区当日 Google 热搜榜单,并通过边缘节点每日静默同步,让搜索行为永远贴合当地当天的真实网络脉搏。
|
- 🔄 **全栈零信任 OTA 引擎 (Zero-Trust OTA Upgrade)**:首创双端物理熔断机制。长官可通过私有中枢,一键向全舰队下发静默热重载指令;更支持**「司令部金蝉脱壳」**,实现真正的全栈去 SSH 化运维。
|
||||||
- 🔀 **[v3.3.0] 智能错峰调度 (Thundering Herd Mitigation)**:首创节点部署时间戳锚定逻辑。边缘节点按需智能分频(每日拉取词库,每月按 30 天周期错峰拉取千万级指纹库),化解“惊群效应”,抹平统一升级时的并发特征,隐匿于无形。
|
- 🛡️ **SSOT 溯源与热更新装甲 (Smooth Upgrade Engine)**:全系脚本彻底消灭硬编码,动态抓取云端版本信标。自带状态机嗅探逻辑,即便是手动在老节点执行安装,也仅需回车瞬间完成配置继承与无损换代。
|
||||||
- 🎯 **[v3.2.2] 多级容灾与高精度探针 (High-Precision Probe)**:重写战报模块与底层协议自适应逻辑,植入多级 ISP 容灾探针链路,并按“底层数据共识原则”智能清洗冗余 AS 号。确保在纯 V6、隧道或弱网环境下,数据获取依然 100% 精准畅通。
|
- 🗺️ **全球拓扑矩阵与活体词库 (Global Nexus)**:接入 GitHub Actions 云端兵工厂,每日静默同步全球各大区真实热搜榜单与高权重本土站点,让伪装行为永远贴合当地网络脉搏。
|
||||||
- 🔄 **[v3.2.2] 平滑热更新装甲 (Smooth Upgrade Engine)**:全系植入状态机嗅探逻辑。再次执行部署脚本时将自动识别并继承历史配置、SQLite 数据库与锚定 IP,一键回车瞬间完成无损换代。
|
- 👻 **绝对时空对齐与高频错峰 (UTC-Seeded Scheduling)**:摒弃传统随机轮询,全栈强制接管底层时钟为**绝对 UTC 时间**。全舰队以 **20 分钟 (每日 72 次)** 的极高密度进行养护巡逻,叠加基于部署锚点的天然削峰与随机防并发休眠,完美化解十万级集群的“惊群效应”与 API 熔断。
|
||||||
- 🖧 **[v3.2.1] 底层路由死锁 (Hard-Bind Routing)**:底层探测引擎强力接管 curl 核心参数 (`--interface`),强制将发出的每一滴伪装流量死死绑定在您设定的物理网卡或隧道 IP 上,彻底杜绝双栈或多网卡环境下的流量溢出漏洞。
|
- 🖧 **极速预检与三级容灾架构 (Fail-Fast & Fallback)**:底层引擎强力接管发包参数 (`--interface`) 的同时,创新引入 **4 秒极速预检 (Fail-Fast)** 雷达与**三级阶梯脱壳**机制。无论是纯 IPv6 孤岛、WARP 劫持死锁还是复杂 NAT 嵌套,系统均能瞬间避开网络黑洞,彻底杜绝探针假死与流量溢出。
|
||||||
- 👻 **[v3.2.0] 设备资产持久化 (Hash-Seeded Persona)**:彻底摒弃随机抽取指纹,引入基于节点物理 IP 的哈希锚定引擎。利用不可变哈希种子,为您的每台 VPS 永久锁定 3 个绝对专属设备,完美构建高权重真实家庭内网画像,根除“僵尸网络”同质化特征!
|
|
||||||
- 🗺️ **[v3.1.0] 全球拓扑矩阵 (Global Nexus)**:守护版图横跨亚、欧、美三大洲。为每个国家注入极其硬核的“原生本地化”搜索词库与本土高权重站点(如政府、权威媒体、高铁网),真正实现拟真融入。
|
|
||||||
|
|
||||||
**—— 💎 骨干基建特征 ——**
|
**—— 💎 骨干基建特征 ——**
|
||||||
- 🏭 **自动化指纹兵工厂**:依托 GitHub Actions CI/CD 流水线,每月 1 日无人值守锻造 4000+ 带绝对物理分区的真实终端设备数据。
|
- 🏭 **全自动云端军工厂 (CI/CD Data Factory)**:依托 GitHub Actions 构建双轨无人值守流水线。**每月 1 日**批量锻造 4000+ 带有绝对物理分区的原生终端指纹库;**每日凌晨 (UTC)** 实时抓取全球各战区 Google 真实热搜榜单与本土骨干新闻 RSS。为前线舰队源源不断地输送最鲜活的伪装弹药。
|
||||||
- 🔒 **叹息之墙 (Zero-Trust HMAC)**:底层通讯引入 时间戳 + HMAC-SHA256 军用级动态签名。指令有效期仅 60 秒(阅后即焚),彻底免疫中间人抓包与重放攻击。
|
- 🔒 **叹息之墙 (Zero-Trust HMAC)**:底层通讯引入 时间戳 + HMAC-SHA256 军用级动态签名。指令有效期仅 60 秒(阅后即焚),未授权请求直接触发系统级 403 物理熔断,彻底免疫中间人抓包与重放攻击。
|
||||||
- ☁️ **云端中枢 (Public Master)**:官方公共机器人 @OmniBeacon_bot,新手免自建,一键接入极速入伍!同时支持硬核极客私有化 SQLite 分布式部署。
|
- ☁️ **云端中枢 (Public Master)**:官方公共机器人 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot) ,新手免自建,一键接入极速入伍!同时支持硬核极客私有化 SQLite 分布式部署。
|
||||||
- 🎮 **TG 战术面板 (Command Center)**:全 Inline Keyboard 交互,一键下发伪装指令、索要战报、毫秒级抓取边缘节点实时运行日志。
|
|
||||||
- 👁️🗨️ **玻璃房透明遥测 (Glasshouse)**:基于 Cloudflare Workers 的全透明计数中枢,绝对零隐私收集,仅作原子累加,底层网关源码全开源。
|
- 👁️🗨️ **玻璃房透明遥测 (Glasshouse)**:基于 Cloudflare Workers 的全透明计数中枢,绝对零隐私收集,仅作原子累加,底层网关源码全开源。
|
||||||
|
|
||||||
## 📂 项目架构 (Monorepo)
|
## 📂 项目架构 (Monorepo)
|
||||||
@@ -38,62 +35,69 @@
|
|||||||
```text
|
```text
|
||||||
📦 IP-Sentinel
|
📦 IP-Sentinel
|
||||||
┣ 📂 .github/workflows/ # 🏭 自动化兵工厂:每月定时触发指纹生成的 CI/CD 流水线
|
┣ 📂 .github/workflows/ # 🏭 自动化兵工厂:每月定时触发指纹生成的 CI/CD 流水线
|
||||||
┣ 📂 master/ # 🧠 司令部:SQLite 存储、TG 监听与 Webhook 调度中心
|
┣ 📂 master/ # 🧠 司令部:SQLite 存储 (含 ip_trend_log 趋势跟踪表)、TG 监听与 Webhook 调度
|
||||||
┣ 📂 core/ # 🛡️ 边缘哨兵:Webhook 被动监听、哈希锚定执行引擎
|
┣ 📂 core/ # 🛡️ 边缘哨兵:Webhook 被动监听、哈希锚定执行引擎 (集成深海声呐探测模块)
|
||||||
┣ 📂 scripts/ # 🐍 兵工厂引擎:基于 Python 的多物理分区 UA 生成器
|
┣ 📂 scripts/ # 🐍 兵工厂引擎:基于 Python 的多物理分区 UA 生成器
|
||||||
┣ 📂 data/ # 🗂️ 全球数据规则库 (动态拓扑)
|
┣ 📂 data/ # 🗂️ 全球数据规则库 (动态拓扑)
|
||||||
┃ ┣ 📜 map.json # 🌍 全球区域大脑 (v3.5.0 大洲战区拓扑)
|
┃ ┣ 📜 map.json # 🌍 全球区域大脑 (v3.5.0 大洲战区拓扑)
|
||||||
┃ ┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
|
┃ ┣ 📂 regions/ # 🧊 冷数据:按 [国家/省州/城市] 深度细分的 LBS 锚点
|
||||||
┃ ┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
|
┃ ┣ 📂 keywords/ # 🔥 热数据:按国家归类的动态搜索词库 (OTA 自动更新)
|
||||||
┃ ┗ 📜 user_agents.txt # 🔥 热数据:由兵工厂每月锻造的绝对坐标专属设备库
|
┃ ┗ 📜 user_agents.txt # 🔥 热数据:由兵工厂每月锻造的绝对坐标专属设备库
|
||||||
┣ 📜 version.txt # 🚩 全球版本信标:SSOT 单一事实来源锚点 (v3.5.0)
|
┣ 📜 version.txt # 🚩 双端版本信标:Agent/Master 独立解耦的 KV 环境配置
|
||||||
┗ 📂 telemetry/ # 👁️🗨️ 玻璃房计划:Cloudflare Workers 透明计数器网关源码
|
┗ 📂 telemetry/ # 👁️🗨️ 玻璃房计划:Cloudflare Workers 透明计数器网关源码
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🚀 极速部署 (Quick Start)
|
## 🚀 极速部署 (Quick Start)
|
||||||
|
> 🛡️ **跨平台装甲支持**:Debian / Ubuntu / CentOS / RHEL / Alpine Linux / Arch Linux
|
||||||
|
系统现提供两种接入模式,请根据您的战术需求选择:
|
||||||
|
|
||||||
v3.5.x 提供了两种接入模式,请根据您的战术需求选择:
|
### 🔹 模式 A:私有独立模式 (全自主、强烈推荐)
|
||||||
|
适合追求绝对数据隐私与舰队最高控制权的领主。
|
||||||
|
|
||||||
### 🔹 模式 A:官方公共模式 (最简、推荐)
|
> ☢️ **核按钮系统已就绪**:采用私有部署,您将解锁 **OTA 远程静默升级** 权限!所有私有前线节点均可通过您的 TG 面板实现一键全网代码热重载换代!
|
||||||
**适合不想折腾、只想快速养护 IP 的新兵。**
|
|
||||||
|
|
||||||
1. **关注机器人**:在 TG 中关注 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot) 并发送 `/start`。
|
|
||||||
2. **部署 Agent**:在目标 VPS 上执行以下指令,安装过程中**直接回车**使用官方机器人,并输入您的 Chat ID:
|
|
||||||
```Bash
|
|
||||||
bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/install.sh)
|
|
||||||
|
|
||||||
|
- **部署 Master (中枢大脑)**:找一台 VPS 作为司令部(仅需部署一台),执行:
|
||||||
|
- [官方部署教程](https://blog.iot-architect.com/engineering-practice/ip-sentinel-master-deployment-guide/)
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/master/install_master.sh -o /tmp/ins_master.sh && sudo bash /tmp/ins_master.sh
|
||||||
```
|
```
|
||||||
3. **激活节点**:安装完成后,您的手机会收到一条 #REGISTER# 暗号,将其转发给机器人即可完成入库。
|
- 部署 Agent (边缘哨兵):在需要养护的机器上执行 Agent 脚本,安装时选择私有独立中枢,并分别输入您自建机器人的 [Token](https://blog.iot-architect.com/engineering-practice/create-private-telegram-bot-via-botfather) 以及您的个人 [Chat ID](https://blog.iot-architect.com/engineering-practice/get-telegram-personal-id-via-userinfobot) :
|
||||||
|
- [官方部署教程](https://blog.iot-architect.com/engineering-practice/ip-sentinel-installation-and-upgrade-guide/)
|
||||||
### 🔸 模式 B:私有独立模式 (全自主、硬核)
|
|
||||||
**适合追求绝对数据隐私、需自建机器人的领主。**
|
|
||||||
|
|
||||||
1. **部署 Master**:找一台 VPS 作为大脑(仅需部署一台),执行:
|
|
||||||
```Bash
|
```Bash
|
||||||
bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/master/install_master.sh)
|
curl -fsSL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/install.sh -o /tmp/ins_agent.sh && sudo bash /tmp/ins_agent.sh
|
||||||
|
|
||||||
```
|
```
|
||||||
2. **部署 Agent**:在需要养护的机器上执行 Agent 脚本,输入您自建机器人的 Token 以及与 Master 一致的配置。
|
- 激活节点:安装完成后,您的手机会收到一条 #REGISTER# 注册暗号,将其转发给您自己的机器人即可完成编队入库。
|
||||||
|
|
||||||
|
### 🔸 模式 B:官方公共模式 (最简体验)
|
||||||
|
适合不想折腾、只想快速体验养护效果的新兵。
|
||||||
|
|
||||||
|
- 关注机器人:在 TG 中关注官方安全网关 [@OmniBeacon_bot](https://t.me/OmniBeacon_bot) 并发送 /start。
|
||||||
|
|
||||||
|
- 部署 Agent:在目标 VPS 上执行以下指令,安装过程中选择官方公共网关,并输入您的 Chat ID:
|
||||||
|
- [官方部署教程](https://blog.iot-architect.com/engineering-practice/ip-sentinel-installation-and-upgrade-guide/)
|
||||||
```Bash
|
```Bash
|
||||||
bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/install.sh)
|
curl -fsSL https://raw.githubusercontent.com/hotyue/IP-Sentinel/main/core/install.sh -o /tmp/ins_agent.sh && sudo bash /tmp/ins_agent.sh
|
||||||
|
|
||||||
```
|
```
|
||||||
3. **激活节点**:同上,将暗号转发给您自己的机器人即可。
|
- 激活节点:同上,将收到的暗号转发给官方机器人即可。
|
||||||
|
|
||||||
### ⚠️ 架构级热升级指引 (Upgrade to v3.5.0)
|
## 🆙 架构级无损热升级指引 (Upgrade Guide)
|
||||||
|
|
||||||
得益于 **v3.5.0 全新引入的 SSOT 版本锚点与状态机路由**,系统升级现已变得极其智能化。
|
### 📡 方式一:OTA 远程静默升级 (私有中枢专属)
|
||||||
|
如果您是私有中枢领主,当司令部首页 (`/start`) 或每日战报提示发现新版本时:
|
||||||
|
|
||||||
**如果您是从远古旧版 (v3.3.1 / v3.3.2) 升级:**
|
1. **升级 Master 司令部自身**:在司令部顶级菜单,点击最上方的 `[ 🆙 升级司令部至 vX.X.X ]`。中枢将释放幽灵进程静默重构,数秒后向您发送捷报。
|
||||||
1. 在终端再次运行对应的官方部署指令。
|
2. **升级全舰队 Agent**:在司令部顶级菜单,点击 `[ ☢️ 全舰队 OTA 热重载 ]`。
|
||||||
2. 脚本会识别到您处于“前版本锚点时代”,会自动为您执行【跨代架构重组】。
|
3. **升级单节点 Agent**:进入 `🌍 全球战区雷达` -> 选择目标节点 -> 在统一终端面板点击 `[ 🆙 OTA 静默升级 ]`。
|
||||||
3. **关键动作**:由于节点命名防撞机制变更,升级后您的 TG 会收到一条新的 `#REGISTER#` 指令,请点击并发送一次以同步新身份。
|
*(⚠️ 节点收到指令后会在后台挂起静默拉取,全程无需登录 SSH,完成后将主动发回心跳确认!)*
|
||||||
4. **清理**:在面板中手动剔除失联的旧节点即可。
|
|
||||||
|
|
||||||
**如果您已处于 v3.4.0+:**
|
### 💻 方式二:SSH 终端平滑直装 (适用于官方网关或老旧节点)
|
||||||
所有的升级已进入**“极致静默平滑模式”**。安装引擎会动态抓取云端 `version.txt`,自动修正本地 `config.conf` 的版本号,一键回车,3 秒即可完成全系组件的热重载换代!
|
如果您的节点不支持 OTA,或者您的节点版本过于陈旧 (如 v3.3.1):
|
||||||
|
|
||||||
🗑️ 一键无痕卸载
|
- 登录该节点的 SSH 终端,再次运行上面的 core/install.sh 官方安装指令。
|
||||||
|
|
||||||
|
- 安装引擎自带状态机嗅探逻辑,它会自动读取老旧数据,您只需一路回车,3 秒即可在本地完成配置继承、数据同步与新内核的无损覆盖热重载!
|
||||||
|
|
||||||
|
## 🗑️ 一键无痕卸载
|
||||||
如果你需要清理某个边缘节点,只需重新运行 `core/install.sh` 并选择 **[2]**,或直接在节点终端执行:
|
如果你需要清理某个边缘节点,只需重新运行 `core/install.sh` 并选择 **[2]**,或直接在节点终端执行:
|
||||||
|
|
||||||
```Bash
|
```Bash
|
||||||
@@ -101,7 +105,7 @@ bash /opt/ip_sentinel/core/uninstall.sh
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🧓 传家宝老旧系统专用通道 (Debian 9)
|
## 🧓 传家宝老旧系统专用通道 (Debian 9)
|
||||||
|
|
||||||
如果你的小鸡系统版本过低(如 Debian 9),由于官方 APT 源已关闭且 Python 版本过旧,无法使用主线版本,请使用 **Legacy 兼容分支** 部署。
|
如果你的小鸡系统版本过低(如 Debian 9),由于官方 APT 源已关闭且 Python 版本过旧,无法使用主线版本,请使用 **Legacy 兼容分支** 部署。
|
||||||
*(注意:该分支仅作基础维护,不享受新功能迭代,请尽可能升级你的系统)*
|
*(注意:该分支仅作基础维护,不享受新功能迭代,请尽可能升级你的系统)*
|
||||||
@@ -110,20 +114,39 @@ bash /opt/ip_sentinel/core/uninstall.sh
|
|||||||
bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/legacy/core/install.sh)
|
bash <(curl -sL https://raw.githubusercontent.com/hotyue/IP-Sentinel/legacy/core/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
📡 战术联络 (Community)
|
## 📡 战术联络 (Community)
|
||||||
|
|
||||||
如果你在使用过程中遇到任何疑难杂症,或者想围观大佬们的养护战报,欢迎加入我们的基地:
|
如果你在使用过程中遇到任何疑难杂症,或者想围观大佬们的养护战报,欢迎加入我们的基地:
|
||||||
- Telegram 频道: [@IP_Sentinel_Matrix](https://t.me/IP_Sentinel_Matrix)
|
- Telegram 频道: [@IP_Sentinel_Matrix](https://t.me/IP_Sentinel_Matrix)
|
||||||
|
|
||||||
🤝 参与贡献
|
## 🤝 参与贡献 (Contributors)
|
||||||
如果你想为项目增加新的节点区域(例如德国、英国、新加坡等),或者提供更丰富的本土化搜索词库,非常欢迎提交 Pull Request!
|
|
||||||
|
|
||||||
**v3.0 全球节点贡献规范:**
|
**🌟 感谢以下所有为 IP-Sentinel 添砖加瓦的指挥官们!** 你们的每一次 PR 都在让这艘战舰的全球雷达覆盖得更广。
|
||||||
|
|
||||||
|
<a href="https://github.com/hotyue/IP-Sentinel/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=hotyue/IP-Sentinel" alt="Contributors" />
|
||||||
|
</a>
|
||||||
|
|
||||||
|
如果你想为项目增加新的节点区域(例如德国、英国、大洋洲等),或者提供更丰富的本土化搜索词库,非常欢迎提交 Pull Request!
|
||||||
|
|
||||||
|
|
||||||
|
> - 感谢 @xykt 本项目IP质量检测采用[xykt/IPQuality](https://github.com/xykt/IPQuality) 脚本!
|
||||||
|
|
||||||
|
**💡 全球节点贡献规范:**
|
||||||
1. 在 `data/regions/国家代码/省州代码/` 目录下新增对应城市的配置 `.json`。
|
1. 在 `data/regions/国家代码/省州代码/` 目录下新增对应城市的配置 `.json`。
|
||||||
2. 在 `data/keywords/` 目录下新增或完善配套国家的词库 `kw_XX.txt`。
|
2. 在 `data/keywords/` 目录下新增或完善配套国家的词库 `kw_XX.txt`。
|
||||||
3. **最重要的一步:** 在 `data/map.json` 中登记你的国家、省州与城市信息。安装脚本将自动读取地图,在全球雷达中点亮你的节点!
|
3. **最重要的一步:** 在 `data/map.json` 中登记你的国家、省州与城市信息。安装脚本将自动读取地图,在全球雷达中点亮你的节点!
|
||||||
|
|
||||||
⚠️ 免责声明
|
## ⚠️ 免责声明
|
||||||
|
|
||||||
本项目仅供网络原理研究、个人 VPS 维护学习使用。请遵守当地法律法规及目标服务商的 TOS(服务条款),切勿用于恶意高频请求或任何非法用途。使用者需自行承担因不当使用造成的 IP 封禁或其他相关风险。
|
本项目仅供网络原理研究、个人 VPS 维护学习使用。请遵守当地法律法规及目标服务商的 TOS(服务条款),切勿用于恶意高频请求或任何非法用途。使用者需自行承担因不当使用造成的 IP 封禁或其他相关风险。
|
||||||
|
|
||||||
|
## 保持联系
|
||||||
|
|
||||||
|
[](https://blog.iot-architect.com)
|
||||||
|
|
||||||
|
如果你觉得这个项目对你有帮助,欢迎关注我的个人博客,我会定期分享技术教程。
|
||||||
|
|
||||||
|
|
||||||
## Stargazers over time
|
## Stargazers over time
|
||||||
[](https://starchart.cc/hotyue/IP-Sentinel)
|
[](https://starchart.cc/hotyue/IP-Sentinel)
|
||||||
@@ -17,14 +17,13 @@ source "$CONFIG_FILE"
|
|||||||
|
|
||||||
# 默认 Webhook 监听端口
|
# 默认 Webhook 监听端口
|
||||||
AGENT_PORT=${AGENT_PORT:-9527}
|
AGENT_PORT=${AGENT_PORT:-9527}
|
||||||
# [v3.4.0 核心] 统一采用防 Markdown 崩溃的中划线连接符
|
# [v3.5.2 核心] 载入不可变主键与可变展示名 (双轨身份)
|
||||||
IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
if [ -z "$NODE_NAME" ]; then
|
||||||
NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}"
|
IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||||
|
NODE_NAME="$(hostname | tr -cd 'a-zA-Z0-9' | cut -c 1-10)-${IP_HASH}"
|
||||||
# --- [重点升级 1: 守护进程防冲突自检] ---
|
|
||||||
if pgrep -f "webhook.py $AGENT_PORT" > /dev/null; then
|
|
||||||
exit 0
|
|
||||||
fi
|
fi
|
||||||
|
NODE_ALIAS="${NODE_ALIAS:-$NODE_NAME}"
|
||||||
|
|
||||||
|
|
||||||
# 1. 尝试获取实时公网 IP
|
# 1. 尝试获取实时公网 IP
|
||||||
RAW_IP=$(curl -${IP_PREF:-4} -s -m 5 api.ip.sb/ip | tr -d '[:space:]')
|
RAW_IP=$(curl -${IP_PREF:-4} -s -m 5 api.ip.sb/ip | tr -d '[:space:]')
|
||||||
@@ -41,27 +40,30 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$AGENT_IP" ]; then
|
if [ -n "$AGENT_IP" ]; then
|
||||||
# --- [重点升级 2: 智能防打扰注册机制] ---
|
|
||||||
LAST_IP=""
|
LAST_IP=""
|
||||||
[ -f "$IP_CACHE" ] && LAST_IP=$(cat "$IP_CACHE" | tr -d '[:space:]')
|
[ -f "$IP_CACHE" ] && LAST_IP=$(cat "$IP_CACHE" | tr -d '[:space:]')
|
||||||
|
|
||||||
# 只有当这是第一次运行,或者公网 IP 发生变动时,才发送 Telegram 申请
|
|
||||||
if [ "$AGENT_IP" != "$LAST_IP" ]; then
|
if [ "$AGENT_IP" != "$LAST_IP" ]; then
|
||||||
# V3.1.3 协议升级: 在底部暗号中精准嵌入 ${REGION_CODE} 大区标识
|
# [静音手术] 仅在本地静默更新 IP 缓存,彻底切除重复的 TG 发信逻辑,做沉默的守夜人
|
||||||
REG_MSG="👋 **[边缘节点接入申请]**%0A大区: \`${REGION_CODE}\`%0A节点: \`${NODE_NAME}\`%0A地址: \`${AGENT_IP}:${AGENT_PORT}\`%0A%0A⚠️ **安全验证**: 为防止非法节点接入,请长按复制下方代码,并**发送给我**以完成最终授权录入:%0A%0A\`#REGISTER#|${REGION_CODE}|${NODE_NAME}|${AGENT_IP}|${AGENT_PORT}\`"
|
|
||||||
|
|
||||||
curl -s -m 5 -X POST "${TG_API_URL}" \
|
|
||||||
-d "chat_id=${CHAT_ID}" \
|
|
||||||
-d "text=${REG_MSG}" \
|
|
||||||
-d "parse_mode=Markdown" > /dev/null
|
|
||||||
|
|
||||||
echo "✅ [Agent] 已向司令部发送接入申请,请在 Telegram 手机端完成授权!"
|
|
||||||
echo "$AGENT_IP" > "$IP_CACHE"
|
echo "$AGENT_IP" > "$IP_CACHE"
|
||||||
|
echo "ℹ️ [Agent] 发现本地 IP 变动,已静默更新缓存: $AGENT_IP"
|
||||||
else
|
else
|
||||||
echo "ℹ️ [Agent] IP 未变动 ($AGENT_IP),跳过重复注册申请。"
|
echo "ℹ️ [Agent] IP 未变动 ($AGENT_IP),继续后台静默监听。"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ================== [v3.6.3 新增: 自动生成自签名 TLS 加密证书] ==================
|
||||||
|
# [修复] 彻底废除官方网关免 TLS 的裸奔逻辑,全网强制生成证书装甲
|
||||||
|
CERT_FILE="${INSTALL_DIR}/core/cert.pem"
|
||||||
|
KEY_FILE="${INSTALL_DIR}/core/key.pem"
|
||||||
|
if [ ! -f "$CERT_FILE" ] || [ ! -f "$KEY_FILE" ]; then
|
||||||
|
echo "🔐 [Agent] 正在生成本地自签名 TLS 加密证书 (2048位 RSA)..."
|
||||||
|
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
|
||||||
|
-keyout "$KEY_FILE" -out "$CERT_FILE" \
|
||||||
|
-subj "/C=US/O=IP-Sentinel/CN=Agent-Sec" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
# 3. 启动轻量级 Python3 Webhook 监听服务 (v3.0.4 动态 HMAC 签名防重放)
|
# 3. 启动轻量级 Python3 Webhook 监听服务 (v3.0.4 动态 HMAC 签名防重放)
|
||||||
cat > "${INSTALL_DIR}/core/webhook.py" << 'EOF'
|
cat > "${INSTALL_DIR}/core/webhook.py" << 'EOF'
|
||||||
import http.server
|
import http.server
|
||||||
@@ -72,7 +74,7 @@ import os
|
|||||||
import html
|
import html
|
||||||
# ================== [v3.0.4 新增密码学与解析依赖] ==================
|
# ================== [v3.0.4 新增密码学与解析依赖] ==================
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.request # [修复] 提升至全局作用域,防止局部变量遮蔽
|
import urllib.request
|
||||||
import hmac
|
import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
import time
|
import time
|
||||||
@@ -80,6 +82,15 @@ import time
|
|||||||
|
|
||||||
PORT = int(sys.argv[1])
|
PORT = int(sys.argv[1])
|
||||||
|
|
||||||
|
# 🛡️ 防重放攻击 (Nonce 缓存池)
|
||||||
|
USED_SIGNS = {}
|
||||||
|
def clean_used_signs():
|
||||||
|
now = time.time()
|
||||||
|
# 清理过期签名 (超 60 秒的安全窗口)
|
||||||
|
expired = [s for s, t in USED_SIGNS.items() if now - t > 65]
|
||||||
|
for s in expired:
|
||||||
|
del USED_SIGNS[s]
|
||||||
|
|
||||||
# 🛡️ 提取全局鉴权 Token (利用 CHAT_ID 作为 PSK 预共享密钥)
|
# 🛡️ 提取全局鉴权 Token (利用 CHAT_ID 作为 PSK 预共享密钥)
|
||||||
AUTH_TOKEN = ""
|
AUTH_TOKEN = ""
|
||||||
if os.path.exists('/opt/ip_sentinel/config.conf'):
|
if os.path.exists('/opt/ip_sentinel/config.conf'):
|
||||||
@@ -109,8 +120,9 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
current_time = int(time.time())
|
||||||
# 校验 2:时间戳防重放 (误差 ±60秒 内有效,拒绝隔夜抓包重放)
|
# 校验 2:时间戳防重放 (误差 ±60秒 内有效,拒绝隔夜抓包重放)
|
||||||
if abs(int(time.time()) - int(req_t)) > 60:
|
if abs(current_time - int(req_t)) > 60:
|
||||||
self.send_response(401)
|
self.send_response(401)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"401 Unauthorized: Request Expired\n")
|
self.wfile.write(b"401 Unauthorized: Request Expired\n")
|
||||||
@@ -119,6 +131,14 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.send_response(401)
|
self.send_response(401)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 校验 2.5:基于 60秒 窗口的精确重放拦截 (拦截 MITM 并发洗劫)
|
||||||
|
clean_used_signs()
|
||||||
|
if req_sign in USED_SIGNS:
|
||||||
|
self.send_response(401)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"401 Unauthorized: Replay Attack Detected\n")
|
||||||
|
return
|
||||||
|
|
||||||
# 校验 3:HMAC 数据完整性与身份合法性校验
|
# 校验 3:HMAC 数据完整性与身份合法性校验
|
||||||
msg = f"{req_path}:{req_t}".encode('utf-8')
|
msg = f"{req_path}:{req_t}".encode('utf-8')
|
||||||
@@ -130,17 +150,20 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"401 Unauthorized: Signature Mismatch\n")
|
self.wfile.write(b"401 Unauthorized: Signature Mismatch\n")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 鉴权通过,记录该签名至防重放内存池
|
||||||
|
USED_SIGNS[req_sign] = current_time
|
||||||
|
|
||||||
# ================== 路由分发 (恢复为安全的精确匹配) ==================
|
# ================== 路由分发 (恢复为安全的精确匹配) ==================
|
||||||
|
|
||||||
# 路由 0: 全局统筹调度 (处理 /trigger_run 一键全节点维护)
|
# 路由 0: 全局统筹调度
|
||||||
if req_path == '/trigger_run':
|
if req_path == '/trigger_run':
|
||||||
if os.path.exists('/opt/ip_sentinel/core/runner.sh'):
|
if os.path.exists('/opt/ip_sentinel/core/runner.sh'):
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"Action Accepted: runner\n")
|
self.wfile.write(b"Action Accepted: runner\n")
|
||||||
subprocess.Popen(['bash', '/opt/ip_sentinel/core/runner.sh'])
|
os.system("nohup bash /opt/ip_sentinel/core/runner.sh >/dev/null 2>&1 &")
|
||||||
else:
|
else:
|
||||||
self.send_response(404)
|
self.send_response(404)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@@ -152,7 +175,7 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"Action Accepted: mod_google\n")
|
self.wfile.write(b"Action Accepted: mod_google\n")
|
||||||
subprocess.Popen(['bash', '/opt/ip_sentinel/core/mod_google.sh'])
|
os.system("nohup bash /opt/ip_sentinel/core/mod_google.sh >/dev/null 2>&1 &")
|
||||||
else:
|
else:
|
||||||
self.send_response(403)
|
self.send_response(403)
|
||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
@@ -166,7 +189,7 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"Action Accepted: mod_trust\n")
|
self.wfile.write(b"Action Accepted: mod_trust\n")
|
||||||
subprocess.Popen(['bash', '/opt/ip_sentinel/core/mod_trust.sh'])
|
os.system("nohup bash /opt/ip_sentinel/core/mod_trust.sh >/dev/null 2>&1 &")
|
||||||
else:
|
else:
|
||||||
self.send_response(403)
|
self.send_response(403)
|
||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
@@ -179,7 +202,7 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
self.send_header("Content-type", "text/plain")
|
self.send_header("Content-type", "text/plain")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(b"Action Accepted: tg_report\n")
|
self.wfile.write(b"Action Accepted: tg_report\n")
|
||||||
subprocess.Popen(['bash', '/opt/ip_sentinel/core/tg_report.sh'])
|
os.system("nohup bash /opt/ip_sentinel/core/tg_report.sh >/dev/null 2>&1 &")
|
||||||
|
|
||||||
# 路由 4: 抓取并回传实时日志
|
# 路由 4: 抓取并回传实时日志
|
||||||
elif req_path == '/trigger_log':
|
elif req_path == '/trigger_log':
|
||||||
@@ -206,31 +229,241 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
if lines:
|
if lines:
|
||||||
log_data = html.escape("".join(lines[-15:]))
|
log_data = html.escape("".join(lines[-15:]))
|
||||||
|
|
||||||
# [v3.4.0 核心] 获取版本与主机名
|
# [v3.5.2 核心] 获取版本与节点展示别名
|
||||||
local_ver = config.get('AGENT_VERSION', '未知')
|
local_ver = config.get('AGENT_VERSION', '未知')
|
||||||
node_hostname = subprocess.check_output(['hostname']).decode('utf-8').strip()[:10]
|
node_alias = config.get('NODE_ALIAS', config.get('NODE_NAME', 'Unknown-Node'))
|
||||||
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>"
|
text_msg = f"📄 <b>[{node_alias}] 实时日志 (v{local_ver}):</b>\n<pre><code>{log_data}</code></pre>"
|
||||||
|
|
||||||
data = urllib.parse.urlencode({
|
# [v4.0.3 体验升级] 引入 json 模块并改用 JSON Payload,挂载返回控制台按钮
|
||||||
|
import json
|
||||||
|
node_name_cb = config.get('NODE_NAME', 'Unknown')
|
||||||
|
payload = {
|
||||||
'chat_id': config.get('CHAT_ID', ''),
|
'chat_id': config.get('CHAT_ID', ''),
|
||||||
'text': text_msg,
|
'text': text_msg,
|
||||||
'parse_mode': 'HTML'
|
'parse_mode': 'HTML',
|
||||||
}).encode('utf-8')
|
'reply_markup': {
|
||||||
|
'inline_keyboard': [[{'text': '⚙️ 调出该节点控制台', 'callback_data': f'manage:{node_name_cb}'}]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data = json.dumps(payload).encode('utf-8')
|
||||||
|
|
||||||
req = urllib.request.Request(
|
req = urllib.request.Request(
|
||||||
config.get('TG_API_URL', ''),
|
config.get('TG_API_URL', ''),
|
||||||
data=data,
|
data=data,
|
||||||
# [动态化] 彻底消灭硬编码,使用运行态版本号
|
# [动态化] 彻底消灭硬编码,使用运行态版本号,并声明 JSON 头
|
||||||
headers={'User-Agent': f'IP-Sentinel-Agent/{local_ver}'}
|
headers={
|
||||||
|
'User-Agent': f'IP-Sentinel-Agent/{local_ver}',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
urllib.request.urlopen(req, timeout=10)
|
urllib.request.urlopen(req, timeout=10)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Log transmission failed: {e}")
|
print(f"Log transmission failed: {e}")
|
||||||
|
|
||||||
|
# ================== [v4.0.0 新增: 触发深海声呐] ==================
|
||||||
|
elif req_path == '/trigger_quality':
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Action Accepted: trigger_quality\n")
|
||||||
|
|
||||||
|
if os.path.exists('/opt/ip_sentinel/core/mod_quality.sh'):
|
||||||
|
os.system("nohup bash /opt/ip_sentinel/core/mod_quality.sh >/dev/null 2>&1 &")
|
||||||
|
# =================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# 路由 5: 节点重命名展示别名同步接口 (Base64 终极防御版)
|
||||||
|
elif req_path == '/trigger_rename':
|
||||||
|
b64_alias = query.get('b64', [''])[0]
|
||||||
|
if not b64_alias:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"400 Bad Request: Alias is empty\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
import re
|
||||||
|
import base64
|
||||||
|
try:
|
||||||
|
# 1. 还原 URL 安全的 Base64 字符并解码 (杜绝乱码与 WAF 拦截)
|
||||||
|
pad = len(b64_alias) % 4
|
||||||
|
if pad > 0:
|
||||||
|
b64_alias += '=' * (4 - pad)
|
||||||
|
b64_alias = b64_alias.replace('-', '+').replace('_', '/')
|
||||||
|
raw_alias = base64.b64decode(b64_alias).decode('utf-8', errors='ignore')
|
||||||
|
|
||||||
|
# 2. 强清洗:杜绝 TG Markdown 崩溃,严格限制中英数,最大20字符
|
||||||
|
decoded_alias = raw_alias.replace('_', '-')
|
||||||
|
safe_alias = re.sub(r'[^a-zA-Z0-9\-\u4e00-\u9fa5]', '', decoded_alias)[:20]
|
||||||
|
|
||||||
|
if safe_alias:
|
||||||
|
# 3. 强容错读写 config.conf (引入 fcntl 排他锁与 r+ 模式防并发清空)
|
||||||
|
config_path = '/opt/ip_sentinel/config.conf'
|
||||||
|
import fcntl
|
||||||
|
with open(config_path, 'r+', encoding='utf-8', errors='ignore') as f:
|
||||||
|
fcntl.flock(f, fcntl.LOCK_EX)
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
alias_found = False
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith('NODE_ALIAS='):
|
||||||
|
lines[i] = f'NODE_ALIAS="{safe_alias}"\n'
|
||||||
|
alias_found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not alias_found:
|
||||||
|
lines.append(f'NODE_ALIAS="{safe_alias}"\n')
|
||||||
|
|
||||||
|
f.seek(0)
|
||||||
|
f.writelines(lines)
|
||||||
|
f.truncate()
|
||||||
|
fcntl.flock(f, fcntl.LOCK_UN)
|
||||||
|
|
||||||
|
# [v3.5.2 极致丝滑] 移除向 TG 推送冗余报文的逻辑,直接向 Master 回执成功状态即可
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Action Accepted: trigger_rename\n")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f"500 Internal Error: {str(e)}\n".encode('utf-8'))
|
||||||
|
return
|
||||||
|
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"400 Bad Request: Invalid Characters\n")
|
||||||
|
|
||||||
|
# ================== [v3.5.3 新增: 模块动态启停接口] ==================
|
||||||
|
elif req_path == '/trigger_toggle':
|
||||||
|
mod_name = query.get('mod', [''])[0]
|
||||||
|
target_state = query.get('state', [''])[0].lower()
|
||||||
|
|
||||||
|
if mod_name not in ['google', 'trust'] or target_state not in ['true', 'false']:
|
||||||
|
self.send_response(400)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"400 Bad Request: Invalid parameters\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
config_key = f"ENABLE_{mod_name.upper()}="
|
||||||
|
|
||||||
|
try:
|
||||||
|
config_path = '/opt/ip_sentinel/config.conf'
|
||||||
|
import fcntl
|
||||||
|
|
||||||
|
with open(config_path, 'r+', encoding='utf-8', errors='ignore') as f:
|
||||||
|
fcntl.flock(f, fcntl.LOCK_EX)
|
||||||
|
lines = f.readlines()
|
||||||
|
|
||||||
|
found = False
|
||||||
|
for i, line in enumerate(lines):
|
||||||
|
if line.startswith(config_key):
|
||||||
|
lines[i] = f'{config_key}"{target_state}"\n'
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not found:
|
||||||
|
lines.append(f'{config_key}"{target_state}"\n')
|
||||||
|
|
||||||
|
f.seek(0)
|
||||||
|
f.writelines(lines)
|
||||||
|
f.truncate()
|
||||||
|
fcntl.flock(f, fcntl.LOCK_UN)
|
||||||
|
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Action Accepted: trigger_toggle\n")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f"500 Internal Error: {str(e)}\n".encode('utf-8'))
|
||||||
|
|
||||||
|
# ================== [v3.6.0 新增: 零信任 OTA 远程静默升级路由] ==================
|
||||||
|
elif req_path == '/trigger_ota':
|
||||||
|
try:
|
||||||
|
# 动态读取最新 config 内存态
|
||||||
|
config_mem = {}
|
||||||
|
config_path = '/opt/ip_sentinel/config.conf'
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
with open(config_path, 'r', errors='ignore') as f:
|
||||||
|
for line in f:
|
||||||
|
line = line.strip()
|
||||||
|
if '=' in line and not line.startswith('#'):
|
||||||
|
key, val = line.split('=', 1)
|
||||||
|
config_mem[key] = val.strip('"\'')
|
||||||
|
|
||||||
|
# 🛡️ 熔断校验 1: Agent 本地是否开启了 OTA 授权
|
||||||
|
if config_mem.get('ENABLE_OTA', 'false').lower() != 'true':
|
||||||
|
self.send_response(403)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"403 Forbidden: OTA Upgrade Disabled locally\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 🛡️ 熔断校验 2: 是否处于官方公共网关下 (强行硬编码拦截)
|
||||||
|
if config_mem.get('TG_TOKEN', '') == 'OFFICIAL_GATEWAY_MODE':
|
||||||
|
self.send_response(403)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"403 Forbidden: OTA strictly disabled under Public Gateway mode\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 校验通过,立即返回 200 回执,释放 Master 连接池
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-type", "text/plain")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Action Accepted: trigger_ota\n")
|
||||||
|
|
||||||
|
# [修复] 逃逸 Systemd Cgroup,并引入 bash -n 语法树校验防砖机制
|
||||||
|
import shutil
|
||||||
|
import base64
|
||||||
|
# 动态提取部署时的源地址,废除强制写死 main 分支,保障隔离测试环境
|
||||||
|
repo_url = "https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
|
if os.path.exists('/opt/ip_sentinel/core/install.sh'):
|
||||||
|
with open('/opt/ip_sentinel/core/install.sh', 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('REPO_RAW_URL='):
|
||||||
|
repo_url = line.split('=', 1)[1].strip('"\'')
|
||||||
|
break
|
||||||
|
|
||||||
|
# 动态构建报错回执文本 (第一层 Base64 隔离换行与特殊字符)
|
||||||
|
err_msg = f"❌ **OTA 熔断告警**\n📍 节点: `{config_mem.get('NODE_ALIAS', '未知')}`\n⚠️ 原因: 脚本语法校验(bash -n)未通过,下载可能不完整。\n🚀 状态: 升级已取消,节点安全。"
|
||||||
|
err_msg_b64 = base64.b64encode(err_msg.encode('utf-8')).decode('utf-8')
|
||||||
|
|
||||||
|
tg_url = config_mem.get('TG_API_URL', '')
|
||||||
|
chat_id = config_mem.get('CHAT_ID', '')
|
||||||
|
|
||||||
|
# [v3.6.3 究极防御] 采用 Base64 将整个 OTA 执行脚本封装 (第二层隔离)
|
||||||
|
# 彻底免疫因为 python 变量掺杂引号而导致的 shell 注入或截断
|
||||||
|
ota_script = f"""
|
||||||
|
export SILENT_OTA="true"
|
||||||
|
curl -fsSL {repo_url}/core/install.sh -o /tmp/ota_agent.sh
|
||||||
|
if bash -n /tmp/ota_agent.sh; then
|
||||||
|
bash /tmp/ota_agent.sh > /opt/ip_sentinel/logs/ota_upgrade.log 2>&1
|
||||||
|
else
|
||||||
|
MSG=$(echo '{err_msg_b64}' | base64 -d)
|
||||||
|
curl -s -m 10 -X POST "{tg_url}" -d "chat_id={chat_id}" -d "text=$MSG" -d "parse_mode=Markdown" > /dev/null 2>&1
|
||||||
|
echo "OTA Checksum Failed: Script corrupted" > /opt/ip_sentinel/logs/ota_upgrade.log
|
||||||
|
fi
|
||||||
|
"""
|
||||||
|
ota_script_b64 = base64.b64encode(ota_script.encode('utf-8')).decode('utf-8')
|
||||||
|
|
||||||
|
# 安全解包并执行
|
||||||
|
if shutil.which("systemd-run"):
|
||||||
|
full_cmd = f"systemd-run --quiet --no-block bash -c \"echo '{ota_script_b64}' | base64 -d | bash\""
|
||||||
|
else:
|
||||||
|
full_cmd = f"nohup bash -c \"echo '{ota_script_b64}' | base64 -d | bash\" >/dev/null 2>&1 &"
|
||||||
|
|
||||||
|
# 彻底统一为 os.system,消灭最后一个可能游离的 Popen 僵尸进程
|
||||||
|
os.system(full_cmd)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.send_response(500)
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(f"500 Internal Error: {str(e)}\n".encode('utf-8'))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.send_response(404)
|
self.send_response(404)
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@@ -240,21 +473,49 @@ class AgentHandler(http.server.BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
import socket
|
import socket
|
||||||
# ================== [v3.0.3 变更: 引入多线程模型抵抗 Slowloris 攻击] ==================
|
# ================== [v3.0.3 变更: 引入多线程模型抵抗 Slowloris 攻击] ==================
|
||||||
class ThreadedDualStackServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||||
allow_reuse_address = True # 开启端口复用,防止热重启时端口冲突
|
allow_reuse_address = True # 开启端口复用,防止热重启时端口冲突
|
||||||
address_family = socket.AF_INET6 if socket.has_ipv6 else socket.AF_INET
|
|
||||||
|
# [核心修复] 显式关闭 V6ONLY 参数,治愈大量云主机纯双栈下的 IPv4 耳聋现象
|
||||||
|
def server_bind(self):
|
||||||
|
if self.address_family == socket.AF_INET6:
|
||||||
|
try:
|
||||||
|
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
super().server_bind()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bind_addr = "::" if socket.has_ipv6 else ""
|
# 1. 优先尝试监听双栈/IPv6
|
||||||
with ThreadedDualStackServer((bind_addr, PORT), AgentHandler) as httpd:
|
ThreadedServer.address_family = socket.AF_INET6
|
||||||
httpd.serve_forever()
|
httpd = ThreadedServer(("::", PORT), AgentHandler)
|
||||||
|
except Exception:
|
||||||
|
# 2. [核心修复 Issue #23] 若系统内核已禁用 IPv6,抛弃报错,智能回退至纯 IPv4 监听
|
||||||
|
ThreadedServer.address_family = socket.AF_INET
|
||||||
|
httpd = ThreadedServer(("0.0.0.0", PORT), AgentHandler)
|
||||||
|
|
||||||
|
# ================== [v3.6.3 核心: 挂载 TLS 加密隧道 (强制装甲版)] ==================
|
||||||
|
import ssl
|
||||||
|
cert_path = '/opt/ip_sentinel/core/cert.pem'
|
||||||
|
key_path = '/opt/ip_sentinel/core/key.pem'
|
||||||
|
|
||||||
|
# 全网强制启用 TLS 装甲,彻底消灭 HTTP 裸奔漏洞
|
||||||
|
if os.path.exists(cert_path) and os.path.exists(key_path):
|
||||||
|
try:
|
||||||
|
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||||
|
context.load_cert_chain(certfile=cert_path, keyfile=key_path)
|
||||||
|
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"SSL 隧道构建失败,退化为 HTTP: {e}")
|
||||||
|
# ======================================================================================
|
||||||
|
|
||||||
|
try:
|
||||||
|
httpd.serve_forever()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
# ====================================================================================
|
# ====================================================================================
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# --- [重点升级 3: 真正的静默后台启动] ---
|
# --- [重点升级 3: 移交系统级守护进程接管 (阻塞模式)] ---
|
||||||
echo "🚀 [Agent] 正在后台启动 Webhook 监听服务 (端口: $AGENT_PORT)..."
|
echo "🚀 [Agent] 正在启动 Webhook 监听服务 (端口: $AGENT_PORT)..."
|
||||||
nohup python3 "${INSTALL_DIR}/core/webhook.py" "$AGENT_PORT" > /dev/null 2>&1 &
|
exec python3 "${INSTALL_DIR}/core/webhook.py" "$AGENT_PORT"
|
||||||
disown 2>/dev/null || true
|
|
||||||
echo "✅ [Agent] 守护进程启动完毕,可安全关闭终端。"
|
|
||||||
784
core/install.sh
784
core/install.sh
@@ -5,104 +5,197 @@
|
|||||||
# 核心功能: 战区分组菜单、模块按需开启、官方机器人一键配置、版本状态机路由
|
# 核心功能: 战区分组菜单、模块按需开启、官方机器人一键配置、版本状态机路由
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 🛑 核心权限防线: 检查是否以 root 权限运行
|
||||||
|
# ==========================================================
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "\033[31m❌ 权限被拒绝: 部署 IP-Sentinel 需要最高系统权限。\033[0m"
|
||||||
|
echo -e "💡 请切换到 root 用户 (执行 su root 或 sudo -i) 后重新运行指令。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 🟢 [防劫持沙盒] 创建具备随机哈希且仅 root 可见的专属安全工作区
|
||||||
|
SECURE_TMP=$(mktemp -d /tmp/ips_install.XXXXXX)
|
||||||
|
# 确保脚本退出、异常中断或被强杀时,自动销毁沙盒,不留痕迹
|
||||||
|
trap 'rm -rf "$SECURE_TMP"' EXIT HUP INT QUIT TERM
|
||||||
|
|
||||||
# 你的 GitHub 仓库 Raw 数据直链前缀
|
# 你的 GitHub 仓库 Raw 数据直链前缀
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
# 临时改为私库地址用于测试
|
|
||||||
# REPO_RAW_URL="https://git.94211762.xyz/hotyue/IP-Sentinel/raw/branch/main"
|
|
||||||
INSTALL_DIR="/opt/ip_sentinel"
|
INSTALL_DIR="/opt/ip_sentinel"
|
||||||
CONFIG_FILE="${INSTALL_DIR}/config.conf"
|
CONFIG_FILE="${INSTALL_DIR}/config.conf"
|
||||||
|
|
||||||
# [核心: 动态获取全局版本控制锚点 (Single Source of Truth)]
|
# [核心: 动态提取 Agent 专属版本锚点 (KV 解析法)]
|
||||||
TARGET_VERSION=$(curl -s -m 3 "${REPO_RAW_URL}/version.txt" | tr -d '[:space:]')
|
# [修复] 增加 -L 与双栈容灾 (-4),解决纯 V6 或 V6 优先机器连接 GitHub Raw 易超时的问题
|
||||||
|
TARGET_VERSION=$( (curl -sL -m 5 "${REPO_RAW_URL}/version.txt" || curl -4 -sL -m 5 "${REPO_RAW_URL}/version.txt") 2>/dev/null | grep "^AGENT_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]')
|
||||||
# 🛡️ 兜底防线:如果网络波动拉取失败,启用内置的安全兜底版本
|
# 🛡️ 兜底防线:如果网络波动拉取失败,启用内置的安全兜底版本
|
||||||
TARGET_VERSION=${TARGET_VERSION:-"3.5.0"}
|
TARGET_VERSION=${TARGET_VERSION:-"4.0.0"}
|
||||||
|
|
||||||
# 轻量级版本号比对函数 (例如: version_lt "3.3.1" "3.4.0" 返回 true)
|
# 轻量级版本号比对函数 (例如: version_lt "3.3.1" "3.4.0" 返回 true)
|
||||||
version_lt() {
|
version_lt() {
|
||||||
test "$(printf '%s\n' "$1" "$2" | sort -V | head -n 1)" = "$1" && test "$1" != "$2"
|
test "$(printf '%s\n' "$1" "$2" | sort -V | head -n 1)" = "$1" && test "$1" != "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "========================================================"
|
# 1. 依赖检查与智能安装 (v3.5.4 兼容性升级: 支持 Alpine, Arch 及更完善的依赖链)
|
||||||
echo " 🛡️ 欢迎使用 IP-Sentinel (边缘节点 Edge Agent)"
|
echo -e "\n[1/7] 正在探测并安装基础环境依赖 (curl, jq, cron, procps, python3)..."
|
||||||
echo " 当前安装包版本: v${TARGET_VERSION}"
|
|
||||||
echo "========================================================"
|
|
||||||
|
|
||||||
# 1. 依赖检查与安装 (新增 python3 用于轻量级 Webhook 服务)
|
# 定义必须检测的核心命令
|
||||||
echo -e "\n[1/7] 正在安装必要环境依赖 (curl, jq, cron, procps, python3)..."
|
REQUIRED_CMDS=("curl" "jq" "crontab" "pgrep" "python3" "openssl")
|
||||||
if [ -f /etc/debian_version ]; then
|
MISSING_CMDS=()
|
||||||
apt-get update -y >/dev/null 2>&1
|
|
||||||
apt-get install -y curl jq cron procps python3 >/dev/null 2>&1
|
# 基础探测:预检查缺失的命令
|
||||||
elif [ -f /etc/redhat-release ]; then
|
for cmd in "${REQUIRED_CMDS[@]}"; do
|
||||||
yum install -y curl jq cronie procps-ng python3 >/dev/null 2>&1
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
systemctl enable crond && systemctl start crond
|
MISSING_CMDS+=("$cmd")
|
||||||
else
|
fi
|
||||||
echo "⚠️ 未知系统,请确保已手动安装 curl, jq, pgrep 和 python3"
|
done
|
||||||
|
|
||||||
|
# 如果有缺失,执行智能安装逻辑
|
||||||
|
if [ ${#MISSING_CMDS[@]} -gt 0 ]; then
|
||||||
|
echo "⏳ 发现缺失依赖: ${MISSING_CMDS[*]},正在尝试自动补齐..."
|
||||||
|
|
||||||
|
# 嗅探包管理器
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
# Debian / Ubuntu 系列
|
||||||
|
apt-get update -y >/dev/null 2>&1
|
||||||
|
# [v3.6.3 抽脂级优化] 注入 --no-install-recommends 拒绝捆绑销售,大幅节省磁盘与内存
|
||||||
|
apt-get install -y --no-install-recommends curl jq cron procps python3 openssl >/dev/null 2>&1
|
||||||
|
systemctl enable cron >/dev/null 2>&1 && systemctl start cron >/dev/null 2>&1
|
||||||
|
|
||||||
|
elif command -v yum >/dev/null 2>&1 || command -v dnf >/dev/null 2>&1; then
|
||||||
|
# RHEL / CentOS / AlmaLinux 系列
|
||||||
|
PKG_MGR="yum"
|
||||||
|
OPT_ARGS=""
|
||||||
|
if command -v dnf >/dev/null 2>&1; then
|
||||||
|
PKG_MGR="dnf"
|
||||||
|
# [v3.6.3 抽脂级优化] 强行关闭 DNF 的弱依赖拉取
|
||||||
|
OPT_ARGS="--setopt=install_weak_deps=False"
|
||||||
|
fi
|
||||||
|
$PKG_MGR install -y $OPT_ARGS curl jq cronie procps-ng python3 openssl >/dev/null 2>&1
|
||||||
|
systemctl enable crond >/dev/null 2>&1 && systemctl start crond >/dev/null 2>&1
|
||||||
|
|
||||||
|
elif command -v apk >/dev/null 2>&1; then
|
||||||
|
# Alpine 本身就是极致精简,无需特殊参数
|
||||||
|
echo "Alpine 探测到系统类型为 Alpine Linux,正在执行轻量级安装..."
|
||||||
|
# [修复] 新版 Alpine 已废弃 dcron。优先尝试 cronie,若失败则信任自带 busybox-cron,并移除屏蔽以便暴露报错
|
||||||
|
apk add --no-cache curl jq cronie procps python3 bash openssl || apk add --no-cache curl jq procps python3 bash openssl
|
||||||
|
mkdir -p /var/spool/cron/crontabs
|
||||||
|
rc-update add crond default >/dev/null 2>&1
|
||||||
|
service crond start >/dev/null 2>&1
|
||||||
|
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then
|
||||||
|
# Arch Linux 系列
|
||||||
|
pacman -Sy --noconfirm curl jq cronie procps-ng python openssl >/dev/null 2>&1
|
||||||
|
mkdir -p /root/.cache/crontab 2>/dev/null
|
||||||
|
systemctl enable cronie >/dev/null 2>&1 && systemctl start cronie >/dev/null 2>&1
|
||||||
|
|
||||||
|
else
|
||||||
|
# 无法识别的系统:退出并给出清晰的引导信息 (同步更新防捆绑参数)
|
||||||
|
echo -e "\033[31m❌ 自动安装失败:系统未知的包管理器。\033[0m"
|
||||||
|
echo -e "\033[33m⚠️ 请根据您的操作系统,手动执行以下安装命令后重新运行本脚本:\033[0m"
|
||||||
|
echo -e " Debian/Ubuntu: \033[36mapt-get update && apt-get install -y --no-install-recommends curl jq cron procps python3 openssl\033[0m"
|
||||||
|
echo -e " CentOS/RHEL: \033[36myum install -y curl jq cronie procps-ng python3 openssl\033[0m"
|
||||||
|
echo -e " Alpine Linux: \033[36mapk add --no-cache curl jq cronie procps python3 bash openssl\033[0m"
|
||||||
|
echo -e " Arch Linux: \033[36mpacman -Sy curl jq cronie procps-ng python openssl\033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 安装后二次复检
|
||||||
|
for cmd in "${REQUIRED_CMDS[@]}"; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo -e "\033[31m❌ 致命错误:核心命令 '$cmd' 仍未找到!\033[0m"
|
||||||
|
echo -e "这通常是因为您的系统源配置错误或缺失基础组件库导致。"
|
||||||
|
echo -e "请手动修复您的包管理器源,或联系 VPS 供应商重新格式化系统。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
echo -e "\033[32m✅ 基础环境检测通过。\033[0m"
|
||||||
|
|
||||||
# 2. 交互式引导与动态地图解析 (v3.0 全球网络)
|
# 2. 交互式引导与动态地图解析 (v3.0 全球网络)
|
||||||
echo -e "\n[2/7] 正在连线云端,拉取全球节点地图..."
|
echo -e "\n[2/7] 正在连线云端,拉取全球节点地图..."
|
||||||
curl -sL "${REPO_RAW_URL}/data/map.json" -o "/tmp/map.json"
|
curl -sL "${REPO_RAW_URL}/data/map.json" -o "${SECURE_TMP}/map.json"
|
||||||
|
if [ ! -s "${SECURE_TMP}/map.json" ]; then
|
||||||
if [ ! -s "/tmp/map.json" ]; then
|
|
||||||
echo -e "\033[31m❌ 拉取全球地图失败!请检查网络或 GitHub 仓库地址。\033[0m"
|
echo -e "\033[31m❌ 拉取全球地图失败!请检查网络或 GitHub 仓库地址。\033[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\n请选择操作:"
|
# ==========================================================
|
||||||
echo " 1) 🚀 部署边缘节点 (进入全球节点配置)"
|
# [v3.6.0 核心] 拦截静默 OTA 升级模式 (强行接管执行流,跳过人工交互)
|
||||||
echo " 2) 🗑️ 一键卸载 IP-Sentinel"
|
# ==========================================================
|
||||||
read -p "请输入选择 [1-2] (默认1): " ACTION_CHOICE
|
if [ "$SILENT_OTA" == "true" ]; then
|
||||||
|
echo -e "\n⏳ [OTA] 静默升级指令已确认,正在剥离控制台交互..."
|
||||||
|
ACTION_CHOICE=1
|
||||||
|
UPGRADE_MODE="true"
|
||||||
|
KEEP_LOGS="true"
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
echo -e "\n请选择操作:"
|
||||||
|
echo " 1) 🚀 部署边缘节点 (进入全球节点配置)"
|
||||||
|
echo " 2) 🗑️ 一键卸载 IP-Sentinel"
|
||||||
|
read -p "请输入选择 [1-2] (默认1): " ACTION_CHOICE
|
||||||
|
|
||||||
if [ "$ACTION_CHOICE" == "2" ]; then
|
# [v3.5.2 修复] 防止用户直接回车导致变量为空,从而漏过下方的平滑升级判定
|
||||||
echo -e "\n⏳ 正在拉取卸载程序..."
|
ACTION_CHOICE=${ACTION_CHOICE:-1}
|
||||||
curl -sL "${REPO_RAW_URL}/core/uninstall.sh" -o "/tmp/ip_uninstall.sh"
|
|
||||||
chmod +x "/tmp/ip_uninstall.sh"
|
|
||||||
bash "/tmp/ip_uninstall.sh"
|
|
||||||
rm -f "/tmp/ip_uninstall.sh"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ================== [v3.2.2 新增: 平滑升级模式嗅探] ==================
|
if [ "$ACTION_CHOICE" == "2" ]; then
|
||||||
UPGRADE_MODE="false"
|
echo -e "\n⏳ 正在拉取卸载程序..."
|
||||||
KEEP_LOGS="true"
|
curl -sL "${REPO_RAW_URL}/core/uninstall.sh" -o "${SECURE_TMP}/ip_uninstall.sh"
|
||||||
|
chmod +x "${SECURE_TMP}/ip_uninstall.sh"
|
||||||
if [ "$ACTION_CHOICE" == "1" ] && [ -f "$CONFIG_FILE" ]; then
|
bash "${SECURE_TMP}/ip_uninstall.sh"
|
||||||
echo -e "\n\033[33m💡 哨兵雷达提示:检测到本机已部署过 IP-Sentinel。\033[0m"
|
rm -f "${SECURE_TMP}/ip_uninstall.sh"
|
||||||
read -p "👉 是否按原配置直接进行平滑升级?(y/n, 默认y): " UPGRADE_CHOICE
|
exit 0
|
||||||
if [[ -z "$UPGRADE_CHOICE" || "$UPGRADE_CHOICE" =~ ^[Yy]$ ]]; then
|
|
||||||
UPGRADE_MODE="true"
|
|
||||||
read -p "👉 是否保留历史运行日志?(y/n, 默认y): " LOG_CHOICE
|
|
||||||
if [[ "$LOG_CHOICE" =~ ^[Nn]$ ]]; then
|
|
||||||
KEEP_LOGS="false"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 将原配置读入环境变量,为后续跳过配置步骤提供燃料
|
|
||||||
source "$CONFIG_FILE"
|
|
||||||
echo -e "\033[32m✅ 已激活 [平滑升级模式],即将跳过基础配置,直接更新核心装甲...\033[0m"
|
|
||||||
else
|
|
||||||
echo -e "\033[33m🔄 您选择了重新配置,旧的哨兵数据将被彻底抹除。\033[0m"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ================== [v3.2.2 新增: 平滑升级模式嗅探] ==================
|
||||||
|
UPGRADE_MODE="false"
|
||||||
|
KEEP_LOGS="true"
|
||||||
|
|
||||||
|
if [ "$ACTION_CHOICE" == "1" ] && [ -f "$CONFIG_FILE" ]; then
|
||||||
|
echo -e "\n\033[33m💡 哨兵雷达提示:检测到本机已部署过 IP-Sentinel。\033[0m"
|
||||||
|
read -p "👉 是否按原配置直接进行平滑升级?(y/n, 默认y): " UPGRADE_CHOICE
|
||||||
|
if [[ -z "$UPGRADE_CHOICE" || "$UPGRADE_CHOICE" =~ ^[Yy]$ ]]; then
|
||||||
|
UPGRADE_MODE="true"
|
||||||
|
read -p "👉 是否保留历史运行日志?(y/n, 默认y): " LOG_CHOICE
|
||||||
|
if [[ "$LOG_CHOICE" =~ ^[Nn]$ ]]; then
|
||||||
|
KEEP_LOGS="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 将原配置读入环境变量,为后续跳过配置步骤提供燃料
|
||||||
|
source "$CONFIG_FILE"
|
||||||
|
echo -e "\033[32m✅ 已激活 [平滑升级模式],即将跳过基础配置,直接更新核心装甲...\033[0m"
|
||||||
|
else
|
||||||
|
echo -e "\033[33m🔄 您选择了重新配置,旧的哨兵数据将被彻底抹除。\033[0m"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# ====================================================================
|
||||||
fi
|
fi
|
||||||
# ====================================================================
|
|
||||||
|
|
||||||
# ================== [v3.1.1/v3.2.2 优化: 安装前环境纯净度清理] ==================
|
# ================== [v3.1.1/v3.2.2 优化: 安装前环境纯净度清理] ==================
|
||||||
echo -e "\n⏳ 正在清理旧版守护进程与冗余任务..."
|
echo -e "\n⏳ 正在清理系统定时任务中的旧版条目..."
|
||||||
# 1. 强制超度可能存活的 Webhook 及各类看门狗进程,释放端口
|
|
||||||
pkill -9 -f "webhook.py" >/dev/null 2>&1 || true
|
|
||||||
pkill -9 -f "agent_daemon.sh" >/dev/null 2>&1 || true
|
|
||||||
pkill -9 -f "runner.sh" >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
# 2. 清除系统定时任务 (Cron) 中的旧版条目
|
# 1. 清除系统定时任务 (Cron) 中的旧版条目 (安全容错版)
|
||||||
if crontab -l >/dev/null 2>&1; then
|
crontab -l 2>/dev/null | grep -v "ip_sentinel" > "${SECURE_TMP}/cron_clean" || true
|
||||||
crontab -l | grep -v "ip_sentinel" > /tmp/cron_clean
|
# [追加 >/dev/null 2>&1 堵死 Alpine 的脏话输出]
|
||||||
crontab /tmp/cron_clean
|
[ -f "${SECURE_TMP}/cron_clean" ] && crontab "${SECURE_TMP}/cron_clean" >/dev/null 2>&1
|
||||||
rm -f /tmp/cron_clean
|
rm -f "${SECURE_TMP}/cron_clean"
|
||||||
fi
|
|
||||||
|
# ==========================================
|
||||||
|
# 🛑 [物理抹除] 彻底扫除 Alpine 系统的底层残留与双路径文件
|
||||||
|
# ==========================================
|
||||||
|
for CRON_FILE in "/var/spool/cron/crontabs/root" "/etc/crontabs/root"; do
|
||||||
|
if [ -f "$CRON_FILE" ]; then
|
||||||
|
grep -v "ip_sentinel" "$CRON_FILE" > "${CRON_FILE}.tmp" 2>/dev/null || true
|
||||||
|
cat "${CRON_FILE}.tmp" > "$CRON_FILE" 2>/dev/null || true
|
||||||
|
rm -f "${CRON_FILE}.tmp" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# 清理 OpenRC 开机启动项
|
||||||
|
rm -f /etc/local.d/ip_sentinel.start 2>/dev/null
|
||||||
|
|
||||||
# 3. 抹除旧版核心代码,杜绝代码冲突 (根据模式分流)
|
# 3. 抹除旧版核心代码,杜绝代码冲突 (根据模式分流)
|
||||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||||
# 升级模式:仅销毁核心引擎,严格保留 config 与 data
|
# [修复] 升级模式:不再提前销毁核心引擎,改为后续下载成功后的原子化替换,彻底防止断网变砖!
|
||||||
rm -rf "${INSTALL_DIR}/core" 2>/dev/null
|
|
||||||
if [ "$KEEP_LOGS" == "false" ]; then
|
if [ "$KEEP_LOGS" == "false" ]; then
|
||||||
rm -rf "${INSTALL_DIR}/logs" 2>/dev/null
|
rm -rf "${INSTALL_DIR}/logs" 2>/dev/null
|
||||||
echo -e "🗑️ 历史日志已按指令清空。"
|
echo -e "🗑️ 历史日志已按指令清空。"
|
||||||
@@ -125,13 +218,13 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
|
|
||||||
# 📍 动态零级菜单:战区(大洲)选择
|
# 📍 动态零级菜单:战区(大洲)选择
|
||||||
echo -e "\n\033[36m📍 【第零级】请选择目标战区 (Continent):\033[0m"
|
echo -e "\n\033[36m📍 【第零级】请选择目标战区 (Continent):\033[0m"
|
||||||
jq -r '.continents[] | "\(.id)|\(.name)"' /tmp/map.json > /tmp/continents.txt
|
jq -r '.continents[] | "\(.id)|\(.name)"' "${SECURE_TMP}/map.json" > "${SECURE_TMP}/continents.txt"
|
||||||
i=1; CONT_MAP=()
|
i=1; CONT_MAP=()
|
||||||
while IFS="|" read -r cont_id cont_name; do
|
while IFS="|" read -r cont_id cont_name; do
|
||||||
echo " $i) $cont_name"
|
echo " $i) $cont_name"
|
||||||
CONT_MAP[$i]="$cont_id"
|
CONT_MAP[$i]="$cont_id"
|
||||||
((i++))
|
((i++))
|
||||||
done < /tmp/continents.txt
|
done < "${SECURE_TMP}/continents.txt"
|
||||||
|
|
||||||
read -p "请输入选择 [1-$((i-1))] (默认1): " CONT_SEL
|
read -p "请输入选择 [1-$((i-1))] (默认1): " CONT_SEL
|
||||||
CONT_SEL=${CONT_SEL:-1}
|
CONT_SEL=${CONT_SEL:-1}
|
||||||
@@ -139,14 +232,14 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
|
|
||||||
# 📍 动态一级菜单:国家选择 (基于选中战区)
|
# 📍 动态一级菜单:国家选择 (基于选中战区)
|
||||||
echo -e "\n\033[36m📍 【第一级】正在检索 [$CONT_ID] 战区下的国家/地区...\033[0m"
|
echo -e "\n\033[36m📍 【第一级】正在检索 [$CONT_ID] 战区下的国家/地区...\033[0m"
|
||||||
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | \"\(.id)|\(.name)|\(.keyword_file)\"" /tmp/map.json > /tmp/countries.txt
|
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | \"\(.id)|\(.name)|\(.keyword_file)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/countries.txt"
|
||||||
i=1; COUNTRY_MAP=(); KEYWORD_MAP=()
|
i=1; COUNTRY_MAP=(); KEYWORD_MAP=()
|
||||||
while IFS="|" read -r c_id c_name k_file; do
|
while IFS="|" read -r c_id c_name k_file; do
|
||||||
echo " $i) $c_name"
|
echo " $i) $c_name"
|
||||||
COUNTRY_MAP[$i]="$c_id"
|
COUNTRY_MAP[$i]="$c_id"
|
||||||
KEYWORD_MAP[$i]="$k_file"
|
KEYWORD_MAP[$i]="$k_file"
|
||||||
((i++))
|
((i++))
|
||||||
done < /tmp/countries.txt
|
done < "${SECURE_TMP}/countries.txt"
|
||||||
|
|
||||||
read -p "请输入选择 [1-$((i-1))] (默认1): " C_SEL
|
read -p "请输入选择 [1-$((i-1))] (默认1): " C_SEL
|
||||||
C_SEL=${C_SEL:-1}
|
C_SEL=${C_SEL:-1}
|
||||||
@@ -156,11 +249,11 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
|
|
||||||
# 📍 动态二级菜单:省/州选择 (基于选中战区和国家)
|
# 📍 动态二级菜单:省/州选择 (基于选中战区和国家)
|
||||||
echo -e "\n\033[36m📍 【第二级】正在检索 [$COUNTRY_ID] 的行政区数据...\033[0m"
|
echo -e "\n\033[36m📍 【第二级】正在检索 [$COUNTRY_ID] 的行政区数据...\033[0m"
|
||||||
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | \"\(.id)|\(.name)\"" /tmp/map.json > /tmp/states.txt
|
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | \"\(.id)|\(.name)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/states.txt"
|
||||||
STATE_COUNT=$(wc -l < /tmp/states.txt)
|
STATE_COUNT=$(wc -l < "${SECURE_TMP}/states.txt")
|
||||||
|
|
||||||
if [ "$STATE_COUNT" -eq 1 ]; then
|
if [ "$STATE_COUNT" -eq 1 ]; then
|
||||||
IFS="|" read -r STATE_ID STATE_NAME < /tmp/states.txt
|
IFS="|" read -r STATE_ID STATE_NAME < "${SECURE_TMP}/states.txt"
|
||||||
echo -e "\033[32m💡 该国家下仅有单一配置 [$STATE_NAME],已自动跃迁。\033[0m"
|
echo -e "\033[32m💡 该国家下仅有单一配置 [$STATE_NAME],已自动跃迁。\033[0m"
|
||||||
else
|
else
|
||||||
i=1; STATE_MAP=()
|
i=1; STATE_MAP=()
|
||||||
@@ -168,7 +261,7 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
echo " $i) $s_name"
|
echo " $i) $s_name"
|
||||||
STATE_MAP[$i]="$s_id"
|
STATE_MAP[$i]="$s_id"
|
||||||
((i++))
|
((i++))
|
||||||
done < /tmp/states.txt
|
done < "${SECURE_TMP}/states.txt"
|
||||||
read -p "请输入选择 [1-$((i-1))] (默认1): " S_SEL
|
read -p "请输入选择 [1-$((i-1))] (默认1): " S_SEL
|
||||||
S_SEL=${S_SEL:-1}
|
S_SEL=${S_SEL:-1}
|
||||||
STATE_ID="${STATE_MAP[$S_SEL]}"
|
STATE_ID="${STATE_MAP[$S_SEL]}"
|
||||||
@@ -176,26 +269,28 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
|
|
||||||
# 📍 动态三级菜单:城市选择 (基于战区、国家、州三层过滤)
|
# 📍 动态三级菜单:城市选择 (基于战区、国家、州三层过滤)
|
||||||
echo -e "\n\033[36m📍 【第三级】请锁定具体城市节点:\033[0m"
|
echo -e "\n\033[36m📍 【第三级】请锁定具体城市节点:\033[0m"
|
||||||
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | select(.id==\"$STATE_ID\") | .cities[] | \"\(.id)|\(.name)\"" /tmp/map.json > /tmp/cities.txt
|
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | select(.id==\"$STATE_ID\") | .cities[] | \"\(.id)|\(.name)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/cities.txt"
|
||||||
CITY_COUNT=$(wc -l < /tmp/cities.txt)
|
CITY_COUNT=$(wc -l < "${SECURE_TMP}/cities.txt")
|
||||||
|
|
||||||
if [ "$CITY_COUNT" -eq 1 ]; then
|
if [ "$CITY_COUNT" -eq 1 ]; then
|
||||||
IFS="|" read -r CITY_ID CITY_NAME < /tmp/cities.txt
|
IFS="|" read -r CITY_ID CITY_NAME < "${SECURE_TMP}/cities.txt"
|
||||||
echo -e "\033[32m💡 该区域下仅有单一城市 [$CITY_NAME],已自动锁定。\033[0m"
|
echo -e "\033[32m💡 该区域下仅有单一城市 [$CITY_NAME],已自动锁定。\033[0m"
|
||||||
else
|
else
|
||||||
i=1; CITY_MAP=()
|
i=1; CITY_MAP=(); CITY_NAME_MAP=()
|
||||||
while IFS="|" read -r c_id c_name; do
|
while IFS="|" read -r c_id c_name; do
|
||||||
echo " $i) $c_name"
|
echo " $i) $c_name"
|
||||||
CITY_MAP[$i]="$c_id"
|
CITY_MAP[$i]="$c_id"
|
||||||
|
CITY_NAME_MAP[$i]="$c_name"
|
||||||
((i++))
|
((i++))
|
||||||
done < /tmp/cities.txt
|
done < "${SECURE_TMP}/cities.txt"
|
||||||
read -p "请输入选择 [1-$((i-1))] (默认1): " CI_SEL
|
read -p "请输入选择 [1-$((i-1))] (默认1): " CI_SEL
|
||||||
CI_SEL=${CI_SEL:-1}
|
CI_SEL=${CI_SEL:-1}
|
||||||
CITY_ID="${CITY_MAP[$CI_SEL]}"
|
CITY_ID="${CITY_MAP[$CI_SEL]}"
|
||||||
|
CITY_NAME="${CITY_NAME_MAP[$CI_SEL]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 清理临时文件 (增加清理 continents.txt)
|
# 清理临时文件 (增加清理 continents.txt)
|
||||||
rm -f /tmp/map.json /tmp/continents.txt /tmp/countries.txt /tmp/states.txt /tmp/cities.txt
|
rm -f "${SECURE_TMP}/map.json" "${SECURE_TMP}/continents.txt" "${SECURE_TMP}/countries.txt" "${SECURE_TMP}/states.txt" "${SECURE_TMP}/cities.txt"
|
||||||
|
|
||||||
# 本地工作目录初始化 (支持 v3.0 的深度层级)
|
# 本地工作目录初始化 (支持 v3.0 的深度层级)
|
||||||
mkdir -p "${INSTALL_DIR}/core"
|
mkdir -p "${INSTALL_DIR}/core"
|
||||||
@@ -203,46 +298,69 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
mkdir -p "${INSTALL_DIR}/data/regions/${COUNTRY_ID}/${STATE_ID}"
|
mkdir -p "${INSTALL_DIR}/data/regions/${COUNTRY_ID}/${STATE_ID}"
|
||||||
mkdir -p "${INSTALL_DIR}/logs"
|
mkdir -p "${INSTALL_DIR}/logs"
|
||||||
|
|
||||||
# 3. 功能模块前置开关 (按需加载)
|
# 3. 功能模块前置开关 (v3.5.3 默认全量加载,后续经由 TG 动态启停)
|
||||||
echo -e "\n[3/7] 请选择需要开启的养护模块 (按需开启,节省资源):"
|
echo -e "\n[3/7] 正在初始化养护模块 (默认全量部署,支持 TG 远程动态启停)..."
|
||||||
echo " 1) 📍 仅开启 [Google 区域纠偏] (默认,适合流媒体解锁机位漂移)"
|
|
||||||
echo " 2) 🛡️ 仅开启 [IP 信用净化] (适合高风险机房 IP 降低 Scamalytics 分数)"
|
|
||||||
echo " 3) 🔥 双管齐下 (同时开启以上两项)"
|
|
||||||
read -p "请输入选择 [1-3] (默认1): " MODULE_CHOICE
|
|
||||||
|
|
||||||
ENABLE_GOOGLE="true"
|
ENABLE_GOOGLE="true"
|
||||||
ENABLE_TRUST="false"
|
ENABLE_TRUST="true"
|
||||||
case ${MODULE_CHOICE:-1} in
|
|
||||||
2) ENABLE_GOOGLE="false"; ENABLE_TRUST="true" ;;
|
|
||||||
3) ENABLE_GOOGLE="true"; ENABLE_TRUST="true" ;;
|
|
||||||
*) ENABLE_GOOGLE="true"; ENABLE_TRUST="false" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# 4. 接入 Master 中枢配置
|
# 4. 接入 Master 中枢配置
|
||||||
echo -e "\n[4/7] 是否接入 Master 司令部?(需要配置与主控相同的 TG 机器人) (y/n)"
|
echo -e "\n[4/7] 是否接入 Master 司令部进行远程联控? (y/n)"
|
||||||
read -p "请输入选择 [y/n] (默认n): " TG_CHOICE
|
read -p "请输入选择 [y/n] (默认n): " TG_CHOICE
|
||||||
TG_TOKEN=""
|
TG_TOKEN=""
|
||||||
CHAT_ID=""
|
CHAT_ID=""
|
||||||
AGENT_PORT="9527"
|
AGENT_PORT="9527"
|
||||||
if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
|
if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
|
||||||
echo -e "\n\033[33m💡 提示:您可以选择使用自己的机器人,或者直接回车使用官方公共机器人。\033[0m"
|
echo -e "\n请选择中枢接入模式 (推荐私有部署,支持后续 OTA 远程静默升级):"
|
||||||
echo -e "\033[33m⚠️ 注意:若使用官方机器人,请务必先在 TG 中关注 @OmniBeacon_bot 并发送 /start\033[0m"
|
echo " 1) 🛡️ 私有独立中枢 (需提供自建 Bot Token,推荐)"
|
||||||
|
echo " 2) ☁️ 官方公共网关 (@OmniBeacon_bot,新手免配置)"
|
||||||
|
read -p "请输入选择 [1-2] (默认1): " MASTER_TYPE
|
||||||
|
MASTER_TYPE=${MASTER_TYPE:-1}
|
||||||
|
|
||||||
read -p "请输入您的 Telegram Bot Token (回车使用官方默认): " USER_TOKEN
|
if [ "$MASTER_TYPE" == "2" ]; then
|
||||||
|
|
||||||
if [ -z "$USER_TOKEN" ]; then
|
|
||||||
TG_TOKEN="OFFICIAL_GATEWAY_MODE"
|
TG_TOKEN="OFFICIAL_GATEWAY_MODE"
|
||||||
TG_API_URL="https://omni-gateway.samanthaestime296.workers.dev"
|
TG_API_URL="https://omni-gateway.samanthaestime296.workers.dev"
|
||||||
|
ENABLE_OTA="false"
|
||||||
echo -e "\033[32m✅ 已自动连接官方安全网关 (@OmniBeacon_bot)。\033[0m"
|
echo -e "\033[32m✅ 已自动连接官方安全网关 (@OmniBeacon_bot)。\033[0m"
|
||||||
echo -e "\033[33m👉 请确保您已关注官方机器人并发送过 /start,否则将无法接收消息。\033[0m"
|
echo -e "\033[33m👉 请确保您已在 TG 中关注官方机器人并发送过 /start,否则将无法接收消息。\033[0m"
|
||||||
|
# [v3.6.0 安全熔断]
|
||||||
|
echo -e "\n\033[33m⚠️ 【安全熔断提示】\033[0m"
|
||||||
|
echo -e "\033[33m由于您使用了官方公共网关,为防止潜在的滥用或供应链风险,本节点的 [OTA 远程升级] 权限已被系统底层强制禁用。\033[0m"
|
||||||
|
echo -e "\033[33m💡 若未来需要启用 OTA,请自建私有中枢后重新部署本节点。\033[0m"
|
||||||
else
|
else
|
||||||
|
# [v3.6.0 优化] 使用 OSC 8 终端超链接协议,实现“点击即打开”的极客交互
|
||||||
|
echo -e "\n\033[36m📘 私有 Bot 创建教程: \033[4m\033]8;;https://blog.iot-architect.com/engineering-practice/create-private-telegram-bot-via-botfather/\033\\👉 [点击此处直接在浏览器中打开] 👈\033]8;;\033\\\033[0m"
|
||||||
|
echo -e "\033[90m (若您的终端较老不支持点击,请手动复制: https://blog.iot-architect.com/engineering-practice/create-private-telegram-bot-via-botfather/ )\033[0m"
|
||||||
|
read -p "请输入您的私有 Telegram Bot Token: " RAW_TOKEN
|
||||||
|
USER_TOKEN=$(echo "$RAW_TOKEN" | tr -cd 'a-zA-Z0-9_:-')
|
||||||
|
# 🛡️ 核心防误触修复:拦截空回车或粘贴换行导致的跳过 Bug
|
||||||
|
while [ -z "$USER_TOKEN" ]; do
|
||||||
|
read -p "⚠️ Token 不能为空或包含非法字符,请重新输入: " RAW_TOKEN
|
||||||
|
USER_TOKEN=$(echo "$RAW_TOKEN" | tr -cd 'a-zA-Z0-9_:-')
|
||||||
|
done
|
||||||
|
|
||||||
TG_TOKEN="$USER_TOKEN"
|
TG_TOKEN="$USER_TOKEN"
|
||||||
TG_API_URL="https://api.telegram.org/bot${TG_TOKEN}/sendMessage"
|
TG_API_URL="https://api.telegram.org/bot${TG_TOKEN}/sendMessage"
|
||||||
echo -e "\033[32m✅ 已记录您的私有机器人 Token。\033[0m"
|
echo -e "\033[32m✅ 已记录您的私有机器人 Token。\033[0m"
|
||||||
|
|
||||||
|
# [v3.6.0] 私有模式开放 OTA 授权向导
|
||||||
|
echo -e "\n\033[36m[4.1/7] OTA 远程静默升级授权\033[0m"
|
||||||
|
echo -e "💡 开启后,您可以在 TG 面板一键将本节点热更新至最新版本。"
|
||||||
|
read -p "是否允许本节点接收 OTA 升级指令?(y/n, 默认y): " OTA_CHOICE
|
||||||
|
if [[ "$OTA_CHOICE" =~ ^[Nn]$ ]]; then
|
||||||
|
ENABLE_OTA="false"
|
||||||
|
echo -e "🛡️ \033[33m已关闭 OTA 权限,本节点未来将只能通过 SSH 手动升级。\033[0m"
|
||||||
|
else
|
||||||
|
ENABLE_OTA="true"
|
||||||
|
echo -e "✅ \033[32m已开启 OTA 权限,核按钮已挂载至您的私有中枢。\033[0m"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\033[33m💡 提示:如果您不知道自己的 Chat ID,可以关注 @userinfobot 获取。\033[0m"
|
echo -e "\n\033[33m💡 提示:如果您不知道下方自己的 Chat ID 是什么,可以关注 @userinfobot 获取。\033[0m"
|
||||||
read -p "请输入你的 Chat ID (与主控一致): " CHAT_ID
|
echo -e "\033[36m📘 查看图文教程: \033[4m\033]8;;https://blog.iot-architect.com/engineering-practice/get-telegram-personal-id-via-userinfobot/\033\\👉 [点击此处直接在浏览器中打开] 👈\033]8;;\033\\\033[0m"
|
||||||
|
echo -e "\033[90m (若您的终端较老不支持点击,请手动复制: https://blog.iot-architect.com/engineering-practice/get-telegram-personal-id-via-userinfobot/ )\033[0m"
|
||||||
|
read -p "请输入你的 Chat ID (必须准确,否则无法联控): " RAW_CHAT_ID
|
||||||
|
# 强制只保留数字和负号,封死注入
|
||||||
|
CHAT_ID=$(echo "$RAW_CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
# ================== [v3.0.3 变更: 智能随机高位端口生成系统] ==================
|
# ================== [v3.0.3 变更: 智能随机高位端口生成系统] ==================
|
||||||
echo -e "\n\033[36m[4.2/7] 正在构建 Webhook 安全通信隧道...\033[0m"
|
echo -e "\n\033[36m[4.2/7] 正在构建 Webhook 安全通信隧道...\033[0m"
|
||||||
@@ -300,7 +418,8 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
|
|
||||||
if [ ${#IP_OPTIONS[@]} -eq 0 ]; then
|
if [ ${#IP_OPTIONS[@]} -eq 0 ]; then
|
||||||
echo -e "\033[33m⚠️ 雷达受阻:未能自动探测到公网 IP,请手动指定。\033[0m"
|
echo -e "\033[33m⚠️ 雷达受阻:未能自动探测到公网 IP,请手动指定。\033[0m"
|
||||||
read -p "请输入您要绑定的公网 IP (v4 或 v6): " PUBLIC_IP
|
read -p "请输入您要绑定的公网 IP (v4 或 v6): " RAW_PUBLIC_IP
|
||||||
|
PUBLIC_IP=$(echo "$RAW_PUBLIC_IP" | tr -cd 'a-fA-F0-9.:[]')
|
||||||
[[ "$PUBLIC_IP" == *":"* ]] && IP_PREF="6" || IP_PREF="4"
|
[[ "$PUBLIC_IP" == *":"* ]] && IP_PREF="6" || IP_PREF="4"
|
||||||
else
|
else
|
||||||
echo "📍 发现可用出口 IP,请选择要注册与养护的锚点:"
|
echo "📍 发现可用出口 IP,请选择要注册与养护的锚点:"
|
||||||
@@ -362,6 +481,25 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
echo -e "\033[32m✅ 哨兵对外联络点已永久锁定至: $SAFE_PUBLIC_IP\033[0m"
|
echo -e "\033[32m✅ 哨兵对外联络点已永久锁定至: $SAFE_PUBLIC_IP\033[0m"
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
|
# ================== [v3.5.2 新增: 节点不可变主键与展示别名] ==================
|
||||||
|
IP_HASH=$(echo "${SAFE_PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||||
|
NODE_NAME="$(hostname | tr -cd 'a-zA-Z0-9' | cut -c 1-10)-${IP_HASH}"
|
||||||
|
NODE_ALIAS="$NODE_NAME"
|
||||||
|
|
||||||
|
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||||
|
echo -e "\n\033[36m[4.8/7] 节点展示别名设定 (用于面板友好显示)...\033[0m"
|
||||||
|
echo -e "💡 系统底层的不可变主键为: \033[33m${NODE_NAME}\033[0m"
|
||||||
|
read -p "请输入节点展示别名 (如'纽约机房', 回车使用默认): " CUSTOM_ALIAS
|
||||||
|
|
||||||
|
if [ -n "$CUSTOM_ALIAS" ]; then
|
||||||
|
# 🛡️ 强制字符清洗:防御 Shell 注入,并限制长度防刷屏
|
||||||
|
NODE_ALIAS=$(echo "$CUSTOM_ALIAS" | tr -d '"'\''\`\$\|&;<>\n\r' | cut -c 1-20)
|
||||||
|
[ -z "$NODE_ALIAS" ] && NODE_ALIAS="$NODE_NAME"
|
||||||
|
fi
|
||||||
|
echo -e "✅ 已锁定节点展示别名: \033[32m$NODE_ALIAS\033[0m"
|
||||||
|
fi
|
||||||
|
# ========================================================================
|
||||||
|
|
||||||
# 5. 远程拉取冷数据并解析固化
|
# 5. 远程拉取冷数据并解析固化
|
||||||
echo -e "\n[5/7] 正在从云端数据仓库拉取 [${CITY_NAME}] 节点的底层规则..."
|
echo -e "\n[5/7] 正在从云端数据仓库拉取 [${CITY_NAME}] 节点的底层规则..."
|
||||||
REGION_JSON_FILE="${INSTALL_DIR}/data/regions/${COUNTRY_ID}/${STATE_ID}/${CITY_ID}.json"
|
REGION_JSON_FILE="${INSTALL_DIR}/data/regions/${COUNTRY_ID}/${STATE_ID}/${CITY_ID}.json"
|
||||||
@@ -405,6 +543,13 @@ LOG_FILE="${INSTALL_DIR}/logs/sentinel.log"
|
|||||||
IP_PREF="$IP_PREF"
|
IP_PREF="$IP_PREF"
|
||||||
PUBLIC_IP="$SAFE_PUBLIC_IP"
|
PUBLIC_IP="$SAFE_PUBLIC_IP"
|
||||||
BIND_IP="$BIND_IP"
|
BIND_IP="$BIND_IP"
|
||||||
|
|
||||||
|
# [v3.5.2新增: 双轨身份系统]
|
||||||
|
NODE_NAME="$NODE_NAME"
|
||||||
|
NODE_ALIAS="$NODE_ALIAS"
|
||||||
|
|
||||||
|
# [v3.6.0新增: OTA 权限标识]
|
||||||
|
ENABLE_OTA="$ENABLE_OTA"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# ================== [v3.0.3 变更: 敏感配置文件权限收敛] ==================
|
# ================== [v3.0.3 变更: 敏感配置文件权限收敛] ==================
|
||||||
@@ -448,83 +593,339 @@ if [ "$UPGRADE_MODE" == "true" ]; then
|
|||||||
BIND_IP="$NEW_BIND_IP"
|
BIND_IP="$NEW_BIND_IP"
|
||||||
else
|
else
|
||||||
# 如果是未来再升级,配置文件已是最新,直接提取变量供安装脚本尾部使用
|
# 如果是未来再升级,配置文件已是最新,直接提取变量供安装脚本尾部使用
|
||||||
SAFE_PUBLIC_IP=$(grep "^PUBLIC_IP=" "$CONFIG_FILE" | cut -d'"' -f2)
|
# [修复] 避免 cut 提取无引号变量失败,直接复用已 source 的原生变量
|
||||||
|
SAFE_PUBLIC_IP="${PUBLIC_IP}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# [v3.5.2 热修复] 兼容老版本没有 NODE_NAME 和 NODE_ALIAS 的情况,无损补齐
|
||||||
|
if ! grep -q "^NODE_NAME=" "$CONFIG_FILE"; then
|
||||||
|
TMP_HASH=$(echo "${SAFE_PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
||||||
|
NODE_NAME="$(hostname | tr -cd 'a-zA-Z0-9' | cut -c 1-10)-${TMP_HASH}"
|
||||||
|
NODE_ALIAS="$NODE_NAME"
|
||||||
|
echo "NODE_NAME=\"$NODE_NAME\"" >> "$CONFIG_FILE"
|
||||||
|
echo "NODE_ALIAS=\"$NODE_ALIAS\"" >> "$CONFIG_FILE"
|
||||||
|
else
|
||||||
|
NODE_NAME=$(grep "^NODE_NAME=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||||
|
NODE_ALIAS=$(grep "^NODE_ALIAS=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||||
|
if [ -z "$NODE_ALIAS" ]; then
|
||||||
|
NODE_ALIAS="$NODE_NAME"
|
||||||
|
echo "NODE_ALIAS=\"$NODE_ALIAS\"" >> "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# [v3.6.0 热修复] 兼容老版本没有 ENABLE_OTA 的情况,无损补齐默认关闭以防滥用
|
||||||
|
if ! grep -q "^ENABLE_OTA=" "$CONFIG_FILE"; then
|
||||||
|
echo "ENABLE_OTA=\"false\"" >> "$CONFIG_FILE"
|
||||||
|
ENABLE_OTA="false"
|
||||||
|
else
|
||||||
|
ENABLE_OTA=$(grep "^ENABLE_OTA=" "$CONFIG_FILE" | cut -d'"' -f2)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
# 6. 拉取全套组件 (按需下载,绝不浪费空间)
|
# 6. 拉取全套组件 (原子化升级,防断网变砖)
|
||||||
echo -e "\n[6/7] 正在根据模块开关部署核心引擎与热数据..."
|
echo -e "\n[6/7] 正在部署核心引擎与热数据..."
|
||||||
# 确保目录在升级模式下也能被正确建立
|
|
||||||
mkdir -p "${INSTALL_DIR}/core"
|
|
||||||
mkdir -p "${INSTALL_DIR}/data/keywords"
|
mkdir -p "${INSTALL_DIR}/data/keywords"
|
||||||
|
|
||||||
# 基础公共组件
|
# [核心修复] 开辟临时下载区,确保下载 100% 成功后再替换旧核心
|
||||||
curl -sL "${REPO_RAW_URL}/core/runner.sh" -o "${INSTALL_DIR}/core/runner.sh"
|
TMP_CORE="${SECURE_TMP}/core_update"
|
||||||
curl -sL "${REPO_RAW_URL}/core/updater.sh" -o "${INSTALL_DIR}/core/updater.sh"
|
mkdir -p "$TMP_CORE"
|
||||||
curl -sL "${REPO_RAW_URL}/core/tg_report.sh" -o "${INSTALL_DIR}/core/tg_report.sh"
|
|
||||||
curl -sL "${REPO_RAW_URL}/core/agent_daemon.sh" -o "${INSTALL_DIR}/core/agent_daemon.sh"
|
|
||||||
curl -sL "${REPO_RAW_URL}/core/uninstall.sh" -o "${INSTALL_DIR}/core/uninstall.sh"
|
|
||||||
curl -sL "${REPO_RAW_URL}/data/user_agents.txt" -o "${INSTALL_DIR}/data/user_agents.txt"
|
|
||||||
|
|
||||||
# 动态按需组件
|
# 拉取核心代码至临时区
|
||||||
if [ "$ENABLE_GOOGLE" == "true" ]; then
|
curl -sL "${REPO_RAW_URL}/core/runner.sh" -o "${TMP_CORE}/runner.sh"
|
||||||
curl -sL "${REPO_RAW_URL}/core/mod_google.sh" -o "${INSTALL_DIR}/core/mod_google.sh"
|
curl -sL "${REPO_RAW_URL}/core/updater.sh" -o "${TMP_CORE}/updater.sh"
|
||||||
# [v3.2.2 修复] 动态匹配词库下载逻辑
|
curl -sL "${REPO_RAW_URL}/core/tg_report.sh" -o "${TMP_CORE}/tg_report.sh"
|
||||||
if [ "$UPGRADE_MODE" == "false" ]; then
|
curl -sL "${REPO_RAW_URL}/core/agent_daemon.sh" -o "${TMP_CORE}/agent_daemon.sh"
|
||||||
curl -sL "${REPO_RAW_URL}/data/keywords/${KEYWORD_FILE}" -o "${INSTALL_DIR}/data/keywords/${KEYWORD_FILE}"
|
curl -sL "${REPO_RAW_URL}/core/uninstall.sh" -o "${TMP_CORE}/uninstall.sh"
|
||||||
else
|
curl -sL "${REPO_RAW_URL}/core/mod_google.sh" -o "${TMP_CORE}/mod_google.sh"
|
||||||
# 升级模式:利用已有的 REGION_CODE 更新通用词库
|
curl -sL "${REPO_RAW_URL}/core/mod_trust.sh" -o "${TMP_CORE}/mod_trust.sh"
|
||||||
curl -sL "${REPO_RAW_URL}/data/keywords/kw_${REGION_CODE}.txt" -o "${INSTALL_DIR}/data/keywords/kw_${REGION_CODE}.txt" 2>/dev/null || true
|
curl -sL "${REPO_RAW_URL}/core/mod_quality.sh" -o "${TMP_CORE}/mod_quality.sh"
|
||||||
fi
|
|
||||||
|
# 🛡️ 防砖终极校验:检查关键文件是否真实存在且不为空
|
||||||
|
if [ ! -s "${TMP_CORE}/runner.sh" ] || [ ! -s "${TMP_CORE}/agent_daemon.sh" ]; then
|
||||||
|
echo -e "\033[31m❌ 致命错误:核心代码拉取失败!网络阻断或 GitHub Raw 异常。\033[0m"
|
||||||
|
echo "🛡️ 防砖机制触发:已中止覆盖,旧版哨兵引擎仍安全存活中。"
|
||||||
|
rm -rf "$TMP_CORE"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$ENABLE_TRUST" == "true" ]; then
|
# 🟢 [原子化交接核心]: 校验完美通过,新代码已在本地备妥!
|
||||||
curl -sL "${REPO_RAW_URL}/core/mod_trust.sh" -o "${INSTALL_DIR}/core/mod_trust.sh"
|
# 此时再以雷霆手段镇压旧进程,杜绝遗言陷阱与断网变砖的可能!
|
||||||
|
echo "⏳ 新引擎校验通过,正在抹杀旧版守护进程..."
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl kill --signal=SIGKILL ip-sentinel-agent-daemon.service >/dev/null 2>&1 || true
|
||||||
|
systemctl stop ip-sentinel-runner.timer ip-sentinel-updater.timer ip-sentinel-report.timer ip-sentinel-agent-daemon.service >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
|
pkill -9 -f "webhook.py" >/dev/null 2>&1 || true
|
||||||
|
pkill -9 -f "agent_daemon.sh" >/dev/null 2>&1 || true
|
||||||
|
pkill -9 -f "runner.sh" >/dev/null 2>&1 || true
|
||||||
|
pkill -9 -f "tg_report.sh" >/dev/null 2>&1 || true
|
||||||
|
pkill -9 -f "updater.sh" >/dev/null 2>&1 || true
|
||||||
|
pkill -9 -f "sentinel_scheduler.sh" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# 执行代码目录的物理替换
|
||||||
|
rm -rf "${INSTALL_DIR}/core" 2>/dev/null
|
||||||
|
mv "$TMP_CORE" "${INSTALL_DIR}/core"
|
||||||
chmod +x ${INSTALL_DIR}/core/*.sh
|
chmod +x ${INSTALL_DIR}/core/*.sh
|
||||||
|
|
||||||
# 7. 配置系统定时任务 (高频调度与看门狗)
|
# 拉取热数据与词库
|
||||||
echo -e "\n[7/7] 正在注入系统定时任务与看门狗进程..."
|
curl -sL "${REPO_RAW_URL}/data/user_agents.txt" -o "${INSTALL_DIR}/data/user_agents.txt"
|
||||||
crontab -l 2>/dev/null | grep -v "ip_sentinel" > /tmp/cron_backup
|
if [ "$UPGRADE_MODE" == "false" ]; then
|
||||||
|
curl -sL "${REPO_RAW_URL}/data/keywords/${KEYWORD_FILE}" -o "${INSTALL_DIR}/data/keywords/${KEYWORD_FILE}"
|
||||||
# 核心养护模块: 每 30 分钟触发一次
|
else
|
||||||
echo "*/30 * * * * ${INSTALL_DIR}/core/runner.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
# 升级模式:利用已有的 REGION_CODE 更新通用词库
|
||||||
# 养料更新模块: (v3.3.0升级) 每天凌晨 3 点触发,由中枢自动进行分频调度
|
curl -sL "${REPO_RAW_URL}/data/keywords/kw_${REGION_CODE}.txt" -o "${INSTALL_DIR}/data/keywords/kw_${REGION_CODE}.txt" 2>/dev/null || true
|
||||||
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
|
|
||||||
# 每天早上 8 点发送昨天的统计战报
|
|
||||||
echo "0 8 * * * ${INSTALL_DIR}/core/tg_report.sh >/dev/null 2>&1" >> /tmp/cron_backup
|
|
||||||
|
|
||||||
# [v3.0.1新增修改 3: 删除原来的 curl 取 IP,直接使用我们上方锁定的 BIND_IP]
|
|
||||||
# 并提前写入 IP 缓存,彻底阻断 agent_daemon 首次启动时的重复推送
|
|
||||||
# [修复竞态]: 提前写入公网 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
|
|
||||||
echo "* * * * * nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> /tmp/cron_backup
|
|
||||||
|
|
||||||
# 安装时立刻启动一次边缘守护进程
|
|
||||||
nohup bash "${INSTALL_DIR}/core/agent_daemon.sh" >/dev/null 2>&1 &
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
crontab /tmp/cron_backup
|
# 7. 配置系统定时任务 (高频调度与看门狗)
|
||||||
rm -f /tmp/cron_backup
|
echo -e "\n[7/7] 正在注入系统守护进程与调度器..."
|
||||||
|
|
||||||
|
# [时钟同步核心] 获取部署时的绝对 UTC 时间锚点,用于打散全球节点的云端拉取并发
|
||||||
|
DEPLOY_UTC_HOUR=$(date -u +%H)
|
||||||
|
DEPLOY_UTC_MIN=$(date -u +%M)
|
||||||
|
|
||||||
|
# [v3.3.0 新增] 初始化 UA 指纹库更新时间戳,确立 30 天滚动周期的计算锚点 (强制 UTC)
|
||||||
|
echo $(date -u +%s) > "${INSTALL_DIR}/core/.ua_last_update"
|
||||||
|
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "💡 检测到 Systemd 环境,正在部署原生守护服务..."
|
||||||
|
|
||||||
|
# 1. Runner 核心养护模块服务与定时器
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-runner.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=IP-Sentinel Runner Service
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
SyslogIdentifier=ip-sentinel
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash ${INSTALL_DIR}/core/runner.sh
|
||||||
|
User=root
|
||||||
|
CPUSchedulingPolicy=idle
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-runner.timer << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Timer for IP-Sentinel Runner Service
|
||||||
|
[Timer]
|
||||||
|
# [频率优化] 改用严格的 20 分钟步进,杜绝 OTA 瞬间的并发走火!
|
||||||
|
OnCalendar=*:0/20
|
||||||
|
RandomizedDelaySec=180
|
||||||
|
Persistent=true
|
||||||
|
Unit=ip-sentinel-runner.service
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 2. Updater 养料更新模块服务与定时器
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-updater.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=IP-Sentinel Updater Service
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
SyslogIdentifier=ip-sentinel
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash ${INSTALL_DIR}/core/updater.sh
|
||||||
|
User=root
|
||||||
|
CPUSchedulingPolicy=idle
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-updater.timer << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Timer for IP-Sentinel Updater Service
|
||||||
|
[Timer]
|
||||||
|
# [绝对 UTC 锚点] 每天精确在部署的时刻触发,实现全球请求的天然削峰
|
||||||
|
OnCalendar=*-*-* ${DEPLOY_UTC_HOUR}:${DEPLOY_UTC_MIN}:00 UTC
|
||||||
|
Persistent=true
|
||||||
|
Unit=ip-sentinel-updater.service
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now ip-sentinel-runner.timer ip-sentinel-updater.timer
|
||||||
|
|
||||||
|
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||||
|
# 3. TG 战报服务与定时器
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-report.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=IP-Sentinel Telegram Report Service
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
SyslogIdentifier=ip-sentinel
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/bin/bash ${INSTALL_DIR}/core/tg_report.sh
|
||||||
|
User=root
|
||||||
|
CPUSchedulingPolicy=idle
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-report.timer << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Timer for IP-Sentinel Telegram Report Service
|
||||||
|
[Timer]
|
||||||
|
# [绝对 UTC 锚点] 全球统一:每天 UTC 16:00 准时向司令部发送战报
|
||||||
|
OnCalendar=*-*-* 16:00:00 UTC
|
||||||
|
Unit=ip-sentinel-report.service
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 4. [排雷修复] Agent Daemon Webhook 监听守护服务 (Type=simple, 常驻执行)
|
||||||
|
cat > /etc/systemd/system/ip-sentinel-agent-daemon.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=IP-Sentinel Agent Daemon Service
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
SyslogIdentifier=ip-sentinel
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/bin/bash ${INSTALL_DIR}/core/agent_daemon.sh
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
User=root
|
||||||
|
CPUSchedulingPolicy=idle
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# [修复竞态]: 提前写入公网 IP 缓存,阻断重复推送
|
||||||
|
# 强制使用无参数 curl 裸奔探测,对齐 agent_daemon 的认知,防止双栈机型 IPv4/v6 认知错乱导致重启误报
|
||||||
|
DAEMON_IP=$( (curl -s -m 5 api.ip.sb/ip || curl -s -m 5 ifconfig.me) 2>/dev/null | tr -d '[:space:]' )
|
||||||
|
[ -n "$DAEMON_IP" ] && echo "$DAEMON_IP" > "${INSTALL_DIR}/core/.last_ip" || echo "$(echo "$SAFE_PUBLIC_IP" | tr -d '[]')" > "${INSTALL_DIR}/core/.last_ip"
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now ip-sentinel-report.timer
|
||||||
|
systemctl enable --now ip-sentinel-agent-daemon.service
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "💡 未检测到 Systemd,正在配置备用调度器 (兼容 Alpine/OpenRC)..."
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 🛑 智能环境嗅探: 判定是否为受限的 Alpine 容器环境
|
||||||
|
# ==========================================
|
||||||
|
IS_RESTRICTED_ALPINE="false"
|
||||||
|
if [ -f /etc/alpine-release ]; then
|
||||||
|
# 探测虚拟化类型:/proc/vz(OpenVZ), environ包含lxc(LXC), /.dockerenv(Docker)
|
||||||
|
if [ -d /proc/vz ] || grep -qa container=lxc /proc/1/environ 2>/dev/null || [ -f /.dockerenv ]; then
|
||||||
|
IS_RESTRICTED_ALPINE="true"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$IS_RESTRICTED_ALPINE" == "true" ]; then
|
||||||
|
echo -e "⚠️ 探测到受限的 LXC/OpenVZ Alpine 环境,系统自带 Cron 极易假死。"
|
||||||
|
echo -e "🔧 自动降维打击:启用 [自定义高可用死循环调度器] 接管全局任务..."
|
||||||
|
|
||||||
|
# 1. 禁用原有的 Cron 大管家 (防止冲突)
|
||||||
|
rc-update del crond default >/dev/null 2>&1 || true
|
||||||
|
rc-service crond stop >/dev/null 2>&1 || true
|
||||||
|
pkill -9 crond >/dev/null 2>&1 || true
|
||||||
|
crontab -l 2>/dev/null | grep -v "ip_sentinel" > "${SECURE_TMP}/cron_clean" || true
|
||||||
|
[ -f "${SECURE_TMP}/cron_clean" ] && crontab "${SECURE_TMP}/cron_clean" >/dev/null 2>&1
|
||||||
|
rm -f "${SECURE_TMP}/cron_clean"
|
||||||
|
|
||||||
|
# 2. 写入我们的死循环守护进程
|
||||||
|
# [极客修复] 将 << 'EOF' 变为 << EOF,以允许在安装时将部署时刻的 DEPLOY_UTC 变量作为硬编码注入脚本中
|
||||||
|
cat > ${INSTALL_DIR}/core/sentinel_scheduler.sh << EOF
|
||||||
|
#!/bin/bash
|
||||||
|
while true; do
|
||||||
|
# 强制获取绝对 UTC 时分,免疫系统错误时区
|
||||||
|
MIN=\$(date -u +%M)
|
||||||
|
HOUR=\$(date -u +%H)
|
||||||
|
# [频率优化] 匹配 20 分钟步进 (00, 20, 40)
|
||||||
|
if [ "\$MIN" == "00" ] || [ "\$MIN" == "20" ] || [ "\$MIN" == "40" ]; then
|
||||||
|
/bin/bash /opt/ip_sentinel/core/runner.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
# [绝对 UTC 锚点] 基于部署时刻的锚点触发热数据更新,天然并发削峰
|
||||||
|
if [ "\$HOUR" == "${DEPLOY_UTC_HOUR}" ] && [ "\$MIN" == "${DEPLOY_UTC_MIN}" ]; then
|
||||||
|
/bin/bash /opt/ip_sentinel/core/updater.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
# [绝对 UTC 锚点] 统一 UTC 16:00 发送战报
|
||||||
|
if [ "\$HOUR" == "16" ] && [ "\$MIN" == "00" ]; then
|
||||||
|
/bin/bash /opt/ip_sentinel/core/tg_report.sh >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
if ! pgrep -f 'webhook.py' >/dev/null; then
|
||||||
|
/bin/bash /opt/ip_sentinel/core/agent_daemon.sh >/dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
sleep 60
|
||||||
|
done
|
||||||
|
EOF
|
||||||
|
chmod +x ${INSTALL_DIR}/core/sentinel_scheduler.sh
|
||||||
|
|
||||||
|
# 3. 写入 OpenRC 开机自启
|
||||||
|
if command -v rc-update >/dev/null 2>&1 && [ -d "/etc/local.d" ]; then
|
||||||
|
echo "nohup bash ${INSTALL_DIR}/core/sentinel_scheduler.sh >/dev/null 2>&1 &" > /etc/local.d/ip_sentinel_scheduler.start
|
||||||
|
chmod +x /etc/local.d/ip_sentinel_scheduler.start
|
||||||
|
rc-update add local default >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
# 连 OpenRC 都没有的极端环境,写入 profile 兜底
|
||||||
|
grep -q "sentinel_scheduler" /etc/profile || echo "nohup bash ${INSTALL_DIR}/core/sentinel_scheduler.sh >/dev/null 2>&1 &" >> /etc/profile
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. 立即后台启动
|
||||||
|
[ -n "$PUBLIC_IP" ] && echo "$PUBLIC_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||||
|
nohup bash ${INSTALL_DIR}/core/sentinel_scheduler.sh >/dev/null 2>&1 &
|
||||||
|
|
||||||
|
else
|
||||||
|
# ==========================================
|
||||||
|
# 🟢 走常规调度路线 (正常的 Linux 或 KVM 型 Alpine)
|
||||||
|
# ==========================================
|
||||||
|
crontab -l 2>/dev/null | grep -v "ip_sentinel" > "${SECURE_TMP}/cron_backup" || true
|
||||||
|
# [频率优化] 调整为 */20
|
||||||
|
echo "*/20 * * * * ${INSTALL_DIR}/core/runner.sh >/dev/null 2>&1" >> "${SECURE_TMP}/cron_backup"
|
||||||
|
# [绝对 UTC 锚点] 每天精确在部署的 UTC 时刻触发
|
||||||
|
echo "${DEPLOY_UTC_MIN} ${DEPLOY_UTC_HOUR} * * * ${INSTALL_DIR}/core/updater.sh >/dev/null 2>&1" >> "${SECURE_TMP}/cron_backup"
|
||||||
|
|
||||||
|
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||||
|
# [绝对 UTC 锚点] 统一 UTC 16:00
|
||||||
|
echo "0 16 * * * ${INSTALL_DIR}/core/tg_report.sh >/dev/null 2>&1" >> "${SECURE_TMP}/cron_backup"
|
||||||
|
echo "$SAFE_PUBLIC_IP" > "${INSTALL_DIR}/core/.last_ip"
|
||||||
|
# [修复竞态]: 提前写入公网 IP 缓存,阻断重复推送
|
||||||
|
# 强制使用无参数 curl 裸奔探测,对齐 agent_daemon 的认知,防止双栈机型 IPv4/v6 认知错乱导致重启误报
|
||||||
|
DAEMON_IP=$( (curl -s -m 5 api.ip.sb/ip || curl -s -m 5 ifconfig.me) 2>/dev/null | tr -d '[:space:]' )
|
||||||
|
[ -n "$DAEMON_IP" ] && echo "$DAEMON_IP" > "${INSTALL_DIR}/core/.last_ip" || echo "$(echo "$SAFE_PUBLIC_IP" | tr -d '[]')" > "${INSTALL_DIR}/core/.last_ip"
|
||||||
|
|
||||||
|
if command -v rc-update >/dev/null 2>&1 && [ -d "/etc/local.d" ]; then
|
||||||
|
echo "nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" > /etc/local.d/ip_sentinel.start
|
||||||
|
chmod +x /etc/local.d/ip_sentinel.start
|
||||||
|
rc-update add local default >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
echo "@reboot nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> "${SECURE_TMP}/cron_backup"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "* * * * * pgrep -f 'webhook.py' >/dev/null || nohup bash ${INSTALL_DIR}/core/agent_daemon.sh >/dev/null 2>&1 &" >> "${SECURE_TMP}/cron_backup"
|
||||||
|
|
||||||
|
nohup bash "${INSTALL_DIR}/core/agent_daemon.sh" >/dev/null 2>&1 &
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -f "${SECURE_TMP}/cron_backup" ] && crontab "${SECURE_TMP}/cron_backup" >/dev/null 2>&1
|
||||||
|
|
||||||
|
if [ -d "/etc/crontabs" ] && [ -f "/var/spool/cron/crontabs/root" ]; then
|
||||||
|
cp -f /var/spool/cron/crontabs/root /etc/crontabs/root 2>/dev/null || true
|
||||||
|
chmod 600 /etc/crontabs/root 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v rc-service >/dev/null 2>&1; then
|
||||||
|
rc-service crond restart >/dev/null 2>&1 || crond -b >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
pkill -9 crond 2>/dev/null || true
|
||||||
|
crond -b >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "${SECURE_TMP}/cron_backup"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# ================== [v3.4.0 核心: 状态机驱动的热更新路由] ==================
|
# ================== [v3.4.0 核心: 状态机驱动的热更新路由] ==================
|
||||||
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
||||||
# 构造当前节点的唯一代号 (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}"
|
# [v3.6.0 核心] 发送携带全套身份属性的注册指令 (追加 ENABLE_OTA 作为第 7 个字段)
|
||||||
|
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${SAFE_PUBLIC_IP}|${AGENT_PORT}|${NODE_ALIAS}|${ENABLE_OTA}"
|
||||||
|
|
||||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||||
# 读取本地老版本号,如果没有则视为远古版本 v3.3.1
|
# 读取本地老版本号,如果没有则视为远古版本 v3.3.1
|
||||||
@@ -532,31 +933,34 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
|||||||
[ -z "$OLD_VERSION" ] && OLD_VERSION="3.3.1"
|
[ -z "$OLD_VERSION" ] && OLD_VERSION="3.3.1"
|
||||||
|
|
||||||
# [路由表 1]: 跨代兼容 (老版本 < v3.3.2)
|
# [路由表 1]: 跨代兼容 (老版本 < v3.3.2)
|
||||||
# 必须强制下发带有 #REGISTER# 的警告,引导长官重新同步哈希身份
|
|
||||||
if version_lt "$OLD_VERSION" "3.3.2"; then
|
if version_lt "$OLD_VERSION" "3.3.2"; then
|
||||||
echo -e "\n📡 [路由枢纽] 正在执行跨代架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
echo -e "\n📡 [路由枢纽] 正在执行跨代架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
||||||
curl -s -X POST "${TG_API_URL}" \
|
TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!*
|
||||||
-d "chat_id=${CHAT_ID}" \
|
📍 节点:\`${NODE_ALIAS}\`
|
||||||
-d "parse_mode=Markdown" \
|
|
||||||
-d "text=✨ *IP-Sentinel 引擎热更新完成!*
|
|
||||||
📍 节点:\`${NODE_NAME}\`
|
|
||||||
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
||||||
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署
|
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署
|
||||||
|
|
||||||
⚠️ *战区架构已重组,请务必点击下方指令并发送,以同步新的防撞档案:*
|
⚠️ *战区架构已重组,请务必点击下方指令并发送,以同步新的防撞档案:*
|
||||||
\`${REG_MSG}\`" >/dev/null 2>&1
|
\`${REG_MSG}\`"
|
||||||
|
|
||||||
|
# [v4.0.3 体验升级] 注入交互式控制台按钮
|
||||||
|
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
|
||||||
|
curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD" >/dev/null 2>&1
|
||||||
|
|
||||||
echo -e "\033[32m✅ 升级通知已推送!请前往 TG 点击注册指令完成身份同步!\033[0m"
|
echo -e "\033[32m✅ 升级通知已推送!请前往 TG 点击注册指令完成身份同步!\033[0m"
|
||||||
|
|
||||||
# [路由表 2]: 现代静默升级 (老版本 >= v3.3.2)
|
# [路由表 2]: 现代静默升级 (老版本 >= v3.3.2)
|
||||||
else
|
else
|
||||||
echo -e "\n📡 [路由枢纽] 正在执行静默平滑升级 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
echo -e "\n📡 [路由枢纽] 正在执行静默平滑升级 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
|
||||||
curl -s -X POST "${TG_API_URL}" \
|
TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!*
|
||||||
-d "chat_id=${CHAT_ID}" \
|
📍 节点:\`${NODE_ALIAS}\`
|
||||||
-d "parse_mode=Markdown" \
|
|
||||||
-d "text=✨ *IP-Sentinel 引擎热更新完成!*
|
|
||||||
📍 节点:\`${NODE_NAME}\`
|
|
||||||
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
🌐 IP:\`${SAFE_PUBLIC_IP}\`
|
||||||
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署" >/dev/null 2>&1
|
🚀 状态:v${TARGET_VERSION} OTA 动态活体引擎已部署"
|
||||||
|
|
||||||
|
# [v4.0.3 体验升级] 注入交互式控制台按钮
|
||||||
|
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
|
||||||
|
curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD" >/dev/null 2>&1
|
||||||
|
|
||||||
echo -e "\033[32m✅ 升级成功通知已推送到您的 Telegram!\033[0m"
|
echo -e "\033[32m✅ 升级成功通知已推送到您的 Telegram!\033[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -571,16 +975,17 @@ if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
|
|||||||
else
|
else
|
||||||
# [全新安装路由]
|
# [全新安装路由]
|
||||||
echo -e "\n📡 正在向指挥部发送注册暗号..."
|
echo -e "\n📡 正在向指挥部发送注册暗号..."
|
||||||
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" \
|
TEXT_MSG="✨ *IP-Sentinel 部署成功!*
|
||||||
-d "chat_id=${CHAT_ID}" \
|
|
||||||
-d "parse_mode=Markdown" \
|
|
||||||
-d "text=✨ *IP-Sentinel 部署成功!*
|
|
||||||
📍 区域:${REGION_NAME}
|
📍 区域:${REGION_NAME}
|
||||||
🌐 IP:${SAFE_PUBLIC_IP}
|
🌐 IP:${SAFE_PUBLIC_IP}
|
||||||
🔌 端口:${AGENT_PORT}
|
🔌 端口:${AGENT_PORT}
|
||||||
|
|
||||||
🔑 *请点击下方指令复制并回复给机器人:*
|
🔑 *请点击下方指令复制并回复给机器人:*
|
||||||
\`${REG_MSG}\`")
|
\`${REG_MSG}\`"
|
||||||
|
|
||||||
|
# [v4.0.3 体验升级] 注入交互式控制台按钮
|
||||||
|
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
|
||||||
|
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD")
|
||||||
|
|
||||||
if echo "$PUSH_RESULT" | grep -q '"ok":true'; then
|
if echo "$PUSH_RESULT" | grep -q '"ok":true'; then
|
||||||
echo -e "\033[32m✅ 注册信息已推送到您的 Telegram,请按指令完成最终激活!\033[0m"
|
echo -e "\033[32m✅ 注册信息已推送到您的 Telegram,请按指令完成最终激活!\033[0m"
|
||||||
@@ -598,7 +1003,7 @@ else
|
|||||||
echo "🎉 边缘节点 (Agent) 部署流程彻底完成!"
|
echo "🎉 边缘节点 (Agent) 部署流程彻底完成!"
|
||||||
fi
|
fi
|
||||||
echo "📍 你的本地守护区域已锁定为: $REGION_NAME"
|
echo "📍 你的本地守护区域已锁定为: $REGION_NAME"
|
||||||
echo "⚙️ 哨兵现已开启 [每30分钟] 的高频高拟真养护循环。"
|
echo "⚙️ 哨兵现已开启 [每20分钟] 的高频高拟真养护循环。"
|
||||||
if [[ -n "$TG_TOKEN" ]]; then
|
if [[ -n "$TG_TOKEN" ]]; then
|
||||||
echo "📡 Webhook 监听已启动 (端口: $AGENT_PORT) 并向中枢发送了注册请求。"
|
echo "📡 Webhook 监听已启动 (端口: $AGENT_PORT) 并向中枢发送了注册请求。"
|
||||||
|
|
||||||
@@ -628,12 +1033,15 @@ echo "🗑️ 若未来需卸载,可重新运行本脚本选择[2]或执行: b
|
|||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
|
|
||||||
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
|
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
|
||||||
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名,不收集IP)..."
|
# [修复] 仅在全新部署时触发统计,平滑升级/OTA 时绝对不触发,防止配额耗尽与数据注水
|
||||||
AGENT_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/agent" || echo "")
|
if [ "$UPGRADE_MODE" == "false" ]; then
|
||||||
|
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名,不收集IP)..."
|
||||||
|
AGENT_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/agent" || echo "")
|
||||||
|
|
||||||
if [ -n "$AGENT_COUNT" ] && [[ "$AGENT_COUNT" =~ ^[0-9]+$ ]]; then
|
if [ -n "$AGENT_COUNT" ] && [[ "$AGENT_COUNT" =~ ^[0-9]+$ ]]; then
|
||||||
echo -e "\033[32m✅ 感谢您成为全球第 ${AGENT_COUNT} 名 IP-Sentinel 哨兵!\033[0m"
|
echo -e "\033[32m✅ 感谢您成为全球第 ${AGENT_COUNT} 名 IP-Sentinel 哨兵!\033[0m"
|
||||||
else
|
else
|
||||||
echo -e "\033[32m✅ 感谢您加入 IP-Sentinel 哨兵阵列!\033[0m"
|
echo -e "\033[32m✅ 感谢您加入 IP-Sentinel 哨兵阵列!\033[0m"
|
||||||
|
fi
|
||||||
|
echo -e "\n"
|
||||||
fi
|
fi
|
||||||
echo -e "\n"
|
|
||||||
@@ -22,9 +22,21 @@ if ! type log >/dev/null 2>&1; then
|
|||||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||||
local local_ver="${AGENT_VERSION:-未知}"
|
local local_ver="${AGENT_VERSION:-未知}"
|
||||||
|
|
||||||
|
# 保证日志目录存在
|
||||||
mkdir -p "${INSTALL_DIR}/logs"
|
mkdir -p "${INSTALL_DIR}/logs"
|
||||||
# 统一日志格式,注入 [版本号] 追踪标识
|
|
||||||
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"
|
# 日志格式注入 [版本号] 追踪标识
|
||||||
|
local core_msg=$(printf "[v%-5s] [%-5s] [%-7s] [%s] %s" "$local_ver" "$2" "$1" "$REGION_CODE" "$3")
|
||||||
|
# [时区对齐] 强制无视本地时区,以绝对 UTC 时间写入日志
|
||||||
|
echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] $core_msg" >> "${INSTALL_DIR}/logs/sentinel.log"
|
||||||
|
|
||||||
|
# 强制推送到 Systemd Journal (如果系统支持)
|
||||||
|
if command -v logger >/dev/null 2>&1; then
|
||||||
|
logger -t ip-sentinel "$core_msg"
|
||||||
|
else
|
||||||
|
# 降级输出到 stdout,让 Systemd 捕获
|
||||||
|
echo "$core_msg"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -97,14 +109,21 @@ CURL_BIND_OPT=""
|
|||||||
DYNAMIC_IP_PREF="-${IP_PREF:-4}" # 默认提取用户配置
|
DYNAMIC_IP_PREF="-${IP_PREF:-4}" # 默认提取用户配置
|
||||||
|
|
||||||
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
||||||
CURL_BIND_OPT="--interface $BIND_IP"
|
# [v3.6.3 容错层补丁] 探测物理网卡/虚拟 IP 存活状态
|
||||||
# 智能探测:带冒号为 V6,带点号为 V4
|
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||||
if [[ "$BIND_IP" == *":"* ]]; then
|
if ! ip addr show 2>/dev/null | grep -qw "$RAW_BIND_IP"; then
|
||||||
DYNAMIC_IP_PREF="-6"
|
log "$MODULE_NAME" "WARN " "检测到配置的出口 IP ($RAW_BIND_IP) 已丢失,自动降级为系统默认路由出网!"
|
||||||
log "$MODULE_NAME" "INFO " "底层路由锁定: 绑定 IPv6 出口及协议 ($BIND_IP)"
|
CURL_BIND_OPT=""
|
||||||
elif [[ "$BIND_IP" == *"."* ]]; then
|
else
|
||||||
DYNAMIC_IP_PREF="-4"
|
CURL_BIND_OPT="--interface $BIND_IP"
|
||||||
log "$MODULE_NAME" "INFO " "底层路由锁定: 绑定 IPv4 出口及协议 ($BIND_IP)"
|
# 智能探测:带冒号为 V6,带点号为 V4
|
||||||
|
if [[ "$BIND_IP" == *":"* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-6"
|
||||||
|
log "$MODULE_NAME" "INFO " "底层路由锁定: 绑定 IPv6 出口及协议 ($BIND_IP)"
|
||||||
|
elif [[ "$BIND_IP" == *"."* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-4"
|
||||||
|
log "$MODULE_NAME" "INFO " "底层路由锁定: 绑定 IPv4 出口及协议 ($BIND_IP)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -143,53 +162,133 @@ for ((i=1; i<=TOTAL_ACTIONS; i++)); do
|
|||||||
|
|
||||||
log "$MODULE_NAME" "EXEC " "动作[$i/$TOTAL_ACTIONS]完成 | HTTP状态: $CODE | 抖动坐标: $ACTION_LAT, $ACTION_LON"
|
log "$MODULE_NAME" "EXEC " "动作[$i/$TOTAL_ACTIONS]完成 | HTTP状态: $CODE | 抖动坐标: $ACTION_LAT, $ACTION_LON"
|
||||||
|
|
||||||
# 【核心升级】行为拉伸:每次动作后强制休眠 90 - 150 秒
|
# 【核心升级】行为拉伸:每次动作后强制休眠 90 - 120 秒
|
||||||
# 结合动作总数,总耗时将稳定在 10 分钟 到 25 分钟之间
|
# 结合动作总数,总耗时将稳定在 10 分钟 到 20 分钟之间
|
||||||
if [ $i -lt $TOTAL_ACTIONS ]; then
|
if [ $i -lt $TOTAL_ACTIONS ]; then
|
||||||
SLEEP_TIME=$((90 + RANDOM % 61))
|
SLEEP_TIME=$((90 + RANDOM % 31))
|
||||||
log "$MODULE_NAME" "WAIT " "阅读当前页面内容,模拟停留 $SLEEP_TIME 秒..."
|
log "$MODULE_NAME" "WAIT " "阅读当前页面内容,模拟停留 $SLEEP_TIME 秒..."
|
||||||
sleep $SLEEP_TIME
|
sleep $SLEEP_TIME
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# --- [结果纠偏自检 (V3.2.1 高精度容错版)] ---
|
# --- [结果纠偏自检 (V4.0.9 终极三核雷达: URL跳转 + Premium + Music)] ---
|
||||||
# [V3.2.1 热修复] 探针同样应用 $DYNAMIC_IP_PREF 协议自适应
|
# 战术揭秘:汲取开源社区顶级探针的精髓!
|
||||||
PROBE_RESULT=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -m 15 -s -L -o /dev/null -w "%{http_code}|%{url_effective}" https://www.google.com)
|
# 1. 传统 URL 跳转探测:捕捉 www.google.com 底层 302 重定向域名的真实归属。
|
||||||
|
# 2. YT Premium 深度探测:提取核心 contentRegion 变量,并强匹配 www.google.cn 送中特征。
|
||||||
|
# 3. 严格一致性校验:任何一端出现非预期偏移,立即判定为漂移,彻底消除虚假“成功”。
|
||||||
|
|
||||||
# 分离状态码与 URL
|
log "$MODULE_NAME" "INFO " "启动三核交叉验证 (URL跳转 + YT Premium + YT Music) 穿透获取 GeoIP..."
|
||||||
PROBE_CODE=$(echo "$PROBE_RESULT" | cut -d'|' -f1)
|
|
||||||
FINAL_URL=$(echo "$PROBE_RESULT" | cut -d'|' -f2)
|
|
||||||
|
|
||||||
# 0. 致命拦截:网络断开、DNS 解析失败或严重超时
|
# 核心 1: 传统 URL 跳转探测 (请求 www 才能触发准确跳转)
|
||||||
if [ "$PROBE_CODE" == "000" ] || [ -z "$FINAL_URL" ]; then
|
JUMP_HDR=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -m 10 -sI "http://www.google.com/")
|
||||||
STATUS="🚨 探针失效 (网络阻断或底层路由异常)"
|
JUMP_LOC=$(echo "$JUMP_HDR" | grep -i "^location:" | tr -d '\r\n')
|
||||||
|
JUMP_GL=""
|
||||||
|
|
||||||
|
if [ -z "$JUMP_LOC" ]; then
|
||||||
|
# 无跳转 (HTTP 200) 通常意味着原生被定位于 US
|
||||||
|
JUMP_GL="US"
|
||||||
|
elif [[ "$JUMP_LOC" == *".google.cn"* ]] || [[ "$JUMP_LOC" == *"gl=CN"* ]]; then
|
||||||
|
JUMP_GL="CN"
|
||||||
|
elif [[ "$JUMP_LOC" == *"gl="* ]]; then
|
||||||
|
JUMP_GL=$(echo "$JUMP_LOC" | grep -o 'gl=[A-Za-z]\{2\}' | head -n 1 | cut -d'=' -f2 | tr 'a-z' 'A-Z')
|
||||||
else
|
else
|
||||||
# 核心战术:精准提取最终 URL 的域名部分
|
# 从域名中提取区域后缀 (如 .co.jp -> JP, .com.hk -> HK, .de -> DE)
|
||||||
ACTUAL_DOMAIN=$(echo "$FINAL_URL" | awk -F/ '{print $3}')
|
JUMP_DOMAIN=$(echo "$JUMP_LOC" | grep -o 'google\.[a-z\.]*' | head -n 1 | sed 's/google\.//')
|
||||||
|
case "$JUMP_DOMAIN" in
|
||||||
# [V3.2.1 优化] 使用通配符 * 剔除任意前缀 (无论是 www.google. 还是 ipv4.google.)
|
"com") JUMP_GL="US" ;;
|
||||||
ACTUAL_SUFFIX=${ACTUAL_DOMAIN#*google.}
|
"com.hk") JUMP_GL="HK" ;;
|
||||||
|
"com.tw") JUMP_GL="TW" ;;
|
||||||
|
"co.jp") JUMP_GL="JP" ;;
|
||||||
|
"co.uk") JUMP_GL="GB" ;;
|
||||||
|
"co.kr") JUMP_GL="KR" ;;
|
||||||
|
"co.in") JUMP_GL="IN" ;;
|
||||||
|
"co.id") JUMP_GL="ID" ;;
|
||||||
|
"co.th") JUMP_GL="TH" ;;
|
||||||
|
"com.sg") JUMP_GL="SG" ;;
|
||||||
|
"com.my") JUMP_GL="MY" ;;
|
||||||
|
"com.au") JUMP_GL="AU" ;;
|
||||||
|
"com.br") JUMP_GL="BR" ;;
|
||||||
|
"com.mx") JUMP_GL="MX" ;;
|
||||||
|
"com.ar") JUMP_GL="AR" ;;
|
||||||
|
"co.za") JUMP_GL="ZA" ;;
|
||||||
|
"cn") JUMP_GL="CN" ;;
|
||||||
|
"") JUMP_GL="" ;;
|
||||||
|
*)
|
||||||
|
# 提取标准两字母后缀 (.de, .fr, .nl)
|
||||||
|
LAST_EXT=$(echo "$JUMP_DOMAIN" | awk -F'.' '{print $NF}' | tr 'a-z' 'A-Z')
|
||||||
|
if [ ${#LAST_EXT} -eq 2 ]; then
|
||||||
|
JUMP_GL="$LAST_EXT"
|
||||||
|
else
|
||||||
|
JUMP_GL="US"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
# 1. 优先验证:绝对匹配目标后缀 (彻底杜绝 com 包含于 com.hk 的陷阱)
|
# 核心 2: YouTube Premium 探测
|
||||||
if [ "$ACTUAL_SUFFIX" == "$VALID_URL_SUFFIX" ]; then
|
YT_PR_GL=""
|
||||||
STATUS="✅ 目标区域达成 ($ACTUAL_SUFFIX)"
|
# [修复] 必须带上本轮循环的专属 UA (-A "$SESSION_UA"),防止被 Google CDN 丢进无状态爬虫兜底页
|
||||||
|
YT_PR_HTML=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -m 10 -s -L -A "$SESSION_UA" "https://www.youtube.com/premium")
|
||||||
|
if echo "$YT_PR_HTML" | grep -q 'www.google.cn'; then
|
||||||
|
YT_PR_GL="CN"
|
||||||
|
else
|
||||||
|
# 穷举风控变量提取
|
||||||
|
YT_PR_GL=$(echo "$YT_PR_HTML" | grep -o '"contentRegion":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
[ -z "$YT_PR_GL" ] && YT_PR_GL=$(echo "$YT_PR_HTML" | grep -o '"countryCode":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
[ -z "$YT_PR_GL" ] && YT_PR_GL=$(echo "$YT_PR_HTML" | grep -o '"INNERTUBE_CONTEXT_GL":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
fi
|
||||||
|
|
||||||
# 2. 核心拦截:精准捕捉送中特征 (com.hk)
|
# 核心 3: YouTube Music 探测
|
||||||
elif [ "$ACTUAL_SUFFIX" == "com.hk" ]; then
|
YT_MU_GL=""
|
||||||
if [ "$REGION_CODE" == "HK" ]; then
|
# [修复] 同样加持 UA 装甲,强行唤出完整版前端框架
|
||||||
STATUS="✅ 目标区域达成 (HK 专属 com.hk)"
|
YT_MU_HTML=$(curl $CURL_BIND_OPT $DYNAMIC_IP_PREF -m 10 -s -L -A "$SESSION_UA" "https://music.youtube.com/")
|
||||||
|
if echo "$YT_MU_HTML" | grep -q 'www.google.cn'; then
|
||||||
|
YT_MU_GL="CN"
|
||||||
|
else
|
||||||
|
# [修复] Music 的核心配置变量是 INNERTUBE_CONTEXT_GL
|
||||||
|
YT_MU_GL=$(echo "$YT_MU_HTML" | grep -o '"INNERTUBE_CONTEXT_GL":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
[ -z "$YT_MU_GL" ] && YT_MU_GL=$(echo "$YT_MU_HTML" | grep -o '"countryCode":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
[ -z "$YT_MU_GL" ] && YT_MU_GL=$(echo "$YT_MU_HTML" | grep -o '"GL":"[A-Za-z]\{2\}"' | head -n 1 | cut -d'"' -f4 | tr 'a-z' 'A-Z')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# [基准对齐] 提取配置大区 (兼容州级穿透),并修正英国的 ISO 代码
|
||||||
|
TARGET_CC="${REGION_CODE%%-*}"
|
||||||
|
[ "$TARGET_CC" == "UK" ] && TARGET_CC="GB"
|
||||||
|
|
||||||
|
# --- 终极审判逻辑 (以 YouTube 核心业务为主导,兼顾底层雷达权重) ---
|
||||||
|
IS_CN=0
|
||||||
|
VALID_PROBES=0
|
||||||
|
|
||||||
|
# 1. 扫描所有探针,统计有效性并执行“送中”一票否决
|
||||||
|
for val in "$JUMP_GL" "$YT_PR_GL" "$YT_MU_GL"; do
|
||||||
|
if [ -n "$val" ]; then
|
||||||
|
((VALID_PROBES++))
|
||||||
|
[ "$val" == "CN" ] && IS_CN=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $VALID_PROBES -eq 0 ]; then
|
||||||
|
STATUS="🚨 探针失效 (三核全部熔断,可能遭严重风控拦截)"
|
||||||
|
elif [ $IS_CN -eq 1 ]; then
|
||||||
|
STATUS="❌ 严重高危!三核雷达判定 IP 已被中国大陆锁定 (送中)!"
|
||||||
|
else
|
||||||
|
# 2. 评估核心流媒体业务是否达标 (只要 YT_PR 或 YT_MU 其一达标,即视为成功)
|
||||||
|
YT_MATCH=0
|
||||||
|
[ "$YT_PR_GL" == "$TARGET_CC" ] && YT_MATCH=1
|
||||||
|
[ "$YT_MU_GL" == "$TARGET_CC" ] && YT_MATCH=1
|
||||||
|
|
||||||
|
if [ $YT_MATCH -eq 1 ]; then
|
||||||
|
# 3. 核心业务达标,进一步评估底层路由权重
|
||||||
|
if [ -n "$JUMP_GL" ] && [ "$JUMP_GL" != "$TARGET_CC" ]; then
|
||||||
|
# YT 解锁了,但基础跳转 IP 库漂移了 (降级为 ✅,但备注底层漂移)
|
||||||
|
STATUS="✅ 目标区域达成 (YT主导成功, Jump副雷达漂移至 ${JUMP_GL}) | Prem: ${YT_PR_GL:-无} | Music: ${YT_MU_GL:-无}"
|
||||||
else
|
else
|
||||||
STATUS="❌ 严重漂移!判定为送中区 (实际跳往 $ACTUAL_SUFFIX)"
|
# 完美达成
|
||||||
|
STATUS="✅ 目标区域达成 (Jump: ${JUMP_GL:-无} | Prem: ${YT_PR_GL:-无} | Music: ${YT_MU_GL:-无})"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. 宽容处理:遵守 Google 无跳转新规 (严格限定必须是纯粹的 com)
|
|
||||||
# [视觉优化] 留在 .com 代表 IP 极度纯净未被区域沙盒锁定,计入成功战绩!
|
|
||||||
elif [ "$ACTUAL_SUFFIX" == "com" ]; then
|
|
||||||
STATUS="✅ 目标区域达成 (免签停留 .com 通用主站)"
|
|
||||||
|
|
||||||
# 4. 跨区漂移:所有预判之外的后缀,全部视为异常
|
|
||||||
else
|
else
|
||||||
STATUS="⚠️ 跨区跳板漂移 (当前实际归属: $ACTUAL_SUFFIX)"
|
# YouTube 流媒体核心未能解锁目标区域,宣判漂移
|
||||||
|
STATUS="⚠️ 区域发生漂移!目标 $TARGET_CC,实际 (Jump: ${JUMP_GL:-无} | Prem: ${YT_PR_GL:-无} | Music: ${YT_MU_GL:-无})"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
266
core/mod_quality.sh
Executable file
266
core/mod_quality.sh
Executable file
@@ -0,0 +1,266 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ==========================================================
|
||||||
|
# IP-Sentinel: 深海声呐 (IP 质量全维异步检测模块 v4.0.0)
|
||||||
|
# ==========================================================
|
||||||
|
|
||||||
|
source /opt/ip_sentinel/config.conf
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 1. 动态网络锚定与协议自适应 (专为多 IP / NAT 架构打造)
|
||||||
|
# ==========================================
|
||||||
|
DYNAMIC_IP_PREF="${IP_PREF:-4}"
|
||||||
|
PROBE_ARGS=("-y" "-j" "-f") # 默认注入: 自动确认、JSON格式、明文无掩码IP
|
||||||
|
|
||||||
|
# 强壮正则:支持 V4, V6 以及带有 [] 护甲的 V6 (兼容多 IP 站群机)
|
||||||
|
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\[\]\.]+$ ]]; then
|
||||||
|
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||||
|
# 严格探测物理网卡/虚拟 IP 存活状态,防止 IP 漂移导致探针彻底报错
|
||||||
|
if ip addr show 2>/dev/null | grep -qw "$RAW_BIND_IP"; then
|
||||||
|
# 恢复使用官方原生参数 -i,不再进行徒劳的底层劫持
|
||||||
|
PROBE_ARGS+=("-i" "$RAW_BIND_IP")
|
||||||
|
|
||||||
|
# 智能识别 V4 / V6,强制覆盖系统默认的 IP_PREF
|
||||||
|
if [[ "$RAW_BIND_IP" == *":"* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="6"
|
||||||
|
elif [[ "$RAW_BIND_IP" == *"."* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="4"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 补齐协议版本参数 (-4 或 -6)
|
||||||
|
PROBE_ARGS+=("-${DYNAMIC_IP_PREF}")
|
||||||
|
|
||||||
|
# 2. 智能拉取引擎 (官方主干优先防 RCE,双栈 CDN 保底,外加文件防伪强校验)
|
||||||
|
PROBE_SCRIPT="/opt/ip_sentinel/core/ip_probe.sh"
|
||||||
|
|
||||||
|
# [校验 1] 验证本地残留脚本是否损坏 (防止之前被墙或拦截返回了 HTML 报错页)
|
||||||
|
if [ -f "$PROBE_SCRIPT" ] && ! grep -q "xykt" "$PROBE_SCRIPT" 2>/dev/null; then
|
||||||
|
rm -f "$PROBE_SCRIPT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -s "$PROBE_SCRIPT" ]; then
|
||||||
|
# 🛡️ 首选防线: 严格遵守从 GitHub 官方主干拉取,捍卫纯净底线
|
||||||
|
curl -sL -m 10 "https://raw.githubusercontent.com/xykt/IPQuality/main/ip.sh" -o "$PROBE_SCRIPT" 2>/dev/null
|
||||||
|
|
||||||
|
# 🚑 文件防伪校验: 如果纯 V6 无法解析 GitHub 返回了 HTML 报错页,剔除它!
|
||||||
|
if ! grep -q "xykt" "$PROBE_SCRIPT" 2>/dev/null; then
|
||||||
|
rm -f "$PROBE_SCRIPT" 2>/dev/null
|
||||||
|
# 降级到双栈 CDN 节点兜底 (仅在 GitHub 彻底失效时启用)
|
||||||
|
curl -sL -m 15 "https://IP.Check.Place" -o "$PROBE_SCRIPT" 2>/dev/null
|
||||||
|
fi
|
||||||
|
chmod +x "$PROBE_SCRIPT" 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 3. 极速预检与容灾打靶系统
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
# 封装链路预检函数 (4秒极速探路,拒绝死等)
|
||||||
|
preflight_check() {
|
||||||
|
local curl_args=("-s" "-m" "4")
|
||||||
|
# 提取网卡和协议约束
|
||||||
|
for ((i=1; i<=$#; i++)); do
|
||||||
|
if [[ "${!i}" == "-i" ]]; then
|
||||||
|
local next=$((i+1))
|
||||||
|
curl_args+=("--interface" "${!next}")
|
||||||
|
elif [[ "${!i}" == "-4" ]]; then
|
||||||
|
curl_args+=("-4")
|
||||||
|
elif [[ "${!i}" == "-6" ]]; then
|
||||||
|
curl_args+=("-6")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# 验证该路由设置是否能成功连通外部网络
|
||||||
|
curl "${curl_args[@]}" "https://www.cloudflare.com/cdn-cgi/trace" >/dev/null 2>&1
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# 📡 寻路雷达:测定哪一组参数可以走通
|
||||||
|
FINAL_ARGS=()
|
||||||
|
if preflight_check "${PROBE_ARGS[@]}"; then
|
||||||
|
# 阶梯 0: 原定参数 (带 BIND_IP 和协议) 通畅
|
||||||
|
FINAL_ARGS=("${PROBE_ARGS[@]}")
|
||||||
|
else
|
||||||
|
# 阶梯 1: 剥离物理网卡限制,只保留协议限制
|
||||||
|
FALLBACK_ARGS=("-y" "-j" "-${DYNAMIC_IP_PREF}")
|
||||||
|
if preflight_check "${FALLBACK_ARGS[@]}"; then
|
||||||
|
FINAL_ARGS=("${FALLBACK_ARGS[@]}")
|
||||||
|
else
|
||||||
|
# 阶梯 2: 终极裸跑 (不限网卡,不限协议)
|
||||||
|
FINAL_ARGS=("-y" "-j")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ==========================================
|
||||||
|
# 4. 终极实弹打靶
|
||||||
|
# ==========================================
|
||||||
|
|
||||||
|
# 此时 FINAL_ARGS 已经被证实是连通的,我们只执行 1 次 ip.sh
|
||||||
|
# 将超时放宽至 300 秒,给第三方 API (如 ipregistry) 充足的响应时间
|
||||||
|
RAW_OUTPUT=$(timeout 300 bash "$PROBE_SCRIPT" "${FINAL_ARGS[@]}" 2>/dev/null)
|
||||||
|
JSON_DATA="{${RAW_OUTPUT#*\{}"
|
||||||
|
ESC=$(printf '\033')
|
||||||
|
JSON_DATA=$(printf "%s" "$JSON_DATA" | sed -e "s/${ESC}\[[0-9;]*[a-zA-Z]//g" -e "s/${ESC}[0-9;]*[a-zA-Z]//g" -e "s/x1b\\[[0-9;]*[a-zA-Z]//g" -e "s/x1b[0-9;]*[a-zA-Z]//g")
|
||||||
|
IP_ADDR=$(echo "$JSON_DATA" | jq -r '.Head.IP // empty' 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$IP_ADDR" ]; then
|
||||||
|
curl -s -X POST "${TG_API_URL}" \
|
||||||
|
-d "chat_id=${CHAT_ID}" \
|
||||||
|
-d "parse_mode=Markdown" \
|
||||||
|
-d "text=❌ *深海声呐探测失败*
|
||||||
|
📍 节点:\`${NODE_ALIAS}\`
|
||||||
|
🌐 锁定IP:\`${PUBLIC_IP}\`
|
||||||
|
⚠️ *未收到有效回波。检测源超时或数据解析受阻。*" >/dev/null
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ASN=$(echo "$JSON_DATA" | jq -r '.Info.ASN // "Unknown"' 2>/dev/null)
|
||||||
|
ORG=$(echo "$JSON_DATA" | jq -r '.Info.Organization // "Unknown"' 2>/dev/null)
|
||||||
|
CITY=$(echo "$JSON_DATA" | jq -r '.Info.City.Name // "Unknown"' 2>/dev/null)
|
||||||
|
COUNTRY=$(echo "$JSON_DATA" | jq -r '.Info.Region.Name // "Unknown"' 2>/dev/null)
|
||||||
|
IP_TYPE=$(echo "$JSON_DATA" | jq -r '.Info.Type // "未知属性"' 2>/dev/null)
|
||||||
|
USAGE_TYPE=$(echo "$JSON_DATA" | jq -r '.Type.Usage.IPinfo // "未知场景"' 2>/dev/null)
|
||||||
|
|
||||||
|
# 3. 深度欺诈与信用评估 (各大权威库联查)
|
||||||
|
SCAM_SCORE=$(echo "$JSON_DATA" | jq -r '.Score.SCAMALYTICS // "0"' 2>/dev/null)
|
||||||
|
ABUSE_SCORE=$(echo "$JSON_DATA" | jq -r '.Score.AbuseIPDB // "0"' 2>/dev/null)
|
||||||
|
IPQS_SCORE=$(echo "$JSON_DATA" | jq -r '.Score.IPQS // "0"' 2>/dev/null)
|
||||||
|
IP2L_SCORE=$(echo "$JSON_DATA" | jq -r '.Score.IP2LOCATION // "0"' 2>/dev/null)
|
||||||
|
FRAUD_RISK=$(echo "$JSON_DATA" | jq -r '.Score.ipapi // "0%"' 2>/dev/null)
|
||||||
|
|
||||||
|
# [修复] 清洗 API 阻断返回的 null 值,保障面板整洁
|
||||||
|
[ "$SCAM_SCORE" == "null" ] || [ -z "$SCAM_SCORE" ] && SCAM_SCORE="N/A"
|
||||||
|
[ "$ABUSE_SCORE" == "null" ] || [ -z "$ABUSE_SCORE" ] && ABUSE_SCORE="N/A"
|
||||||
|
[ "$IPQS_SCORE" == "null" ] || [ -z "$IPQS_SCORE" ] && IPQS_SCORE="N/A"
|
||||||
|
[ "$IP2L_SCORE" == "null" ] || [ -z "$IP2L_SCORE" ] && IP2L_SCORE="N/A"
|
||||||
|
[ "$FRAUD_RISK" == "null" ] || [ -z "$FRAUD_RISK" ] && FRAUD_RISK="N/A"
|
||||||
|
|
||||||
|
# 代理/VPN 特征探针 (只要有一家认为是代理,就亮黄灯)
|
||||||
|
IS_PROXY="🟢 干净"
|
||||||
|
if echo "$JSON_DATA" | jq -e '.Factor.Proxy | to_entries | any(.value == true)' >/dev/null 2>&1 || \
|
||||||
|
echo "$JSON_DATA" | jq -e '.Factor.VPN | to_entries | any(.value == true)' >/dev/null 2>&1; then
|
||||||
|
IS_PROXY="🟡 疑似代理/VPN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. 提取流媒体与 AI 解锁指标 (带解锁类型)
|
||||||
|
parse_media() {
|
||||||
|
local status=$(echo "$JSON_DATA" | jq -r ".Media.$1.Status // \"未知\"" 2>/dev/null)
|
||||||
|
local reg=$(echo "$JSON_DATA" | jq -r ".Media.$1.Region // \"\"" 2>/dev/null)
|
||||||
|
local type=$(echo "$JSON_DATA" | jq -r ".Media.$1.Type // \"\"" 2>/dev/null)
|
||||||
|
|
||||||
|
if [[ "$status" == *"解锁"* ]]; then
|
||||||
|
echo "🟢 ${reg} (${type})"
|
||||||
|
elif [[ "$status" == *"仅"* ]] || [[ "$status" == *"机房"* ]] || [[ "$status" == *"待支持"* ]]; then
|
||||||
|
# 捕捉 Netflix "仅自制"、ChatGPT "仅网页"、TikTok "机房" 等半残状态
|
||||||
|
echo "🟡 ${status} ${reg}"
|
||||||
|
elif [[ "$status" == *"屏蔽"* ]] || [[ "$status" == *"失败"* ]] || [[ "$status" == *"中国"* ]] || [[ "$status" == *"禁"* ]]; then
|
||||||
|
# 捕捉 "屏蔽"、"失败"、"禁会员"、"中国"(送中)
|
||||||
|
echo "🔴 ${status}"
|
||||||
|
else
|
||||||
|
echo "⚪ ${status}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
NF_STAT=$(parse_media "Netflix")
|
||||||
|
YT_STAT=$(parse_media "Youtube")
|
||||||
|
DP_STAT=$(parse_media "DisneyPlus")
|
||||||
|
TK_STAT=$(parse_media "TikTok")
|
||||||
|
GPT_STAT=$(parse_media "ChatGPT")
|
||||||
|
APV_STAT=$(parse_media "AmazonPrimeVideo")
|
||||||
|
|
||||||
|
# 提取原生 JSON 里的原始状态用于底层隐写回传
|
||||||
|
RAW_NF_STAT=$(echo "$JSON_DATA" | jq -r '.Media.Netflix.Status // "Unknown"' 2>/dev/null)
|
||||||
|
RAW_YT_REG=$(echo "$JSON_DATA" | jq -r '.Media.Youtube.Region // ""' 2>/dev/null)
|
||||||
|
RAW_YT_STAT=$(echo "$JSON_DATA" | jq -r '.Media.Youtube.Status // "Unknown"' 2>/dev/null)
|
||||||
|
|
||||||
|
# 5. 邮局连通性与黑名单
|
||||||
|
PORT25=$(echo "$JSON_DATA" | jq -r '.Mail.Port25 // "false"' 2>/dev/null)
|
||||||
|
[ "$PORT25" == "true" ] && P25_TEXT="✅ 畅通" || P25_TEXT="❌ 封堵"
|
||||||
|
DNS_BLACK=$(echo "$JSON_DATA" | jq -r '.Mail.DNSBlacklist.Blacklisted // "0"' 2>/dev/null)
|
||||||
|
DNS_MARK=$(echo "$JSON_DATA" | jq -r '.Mail.DNSBlacklist.Marked // "0"' 2>/dev/null)
|
||||||
|
|
||||||
|
# 6. “送中” 逻辑判定
|
||||||
|
WARNING_MSG=""
|
||||||
|
# [修复] 官方 JSON 已经去除了方括号,直接匹配 CN 或者状态包含中国
|
||||||
|
if [[ "$RAW_YT_REG" == "CN" ]] || [[ "$RAW_YT_STAT" == *"中国"* ]]; then
|
||||||
|
# [修复] 采用 Bash 扩展转义 ($'...'),彻底解决直接打印 \n 字符的问题
|
||||||
|
WARNING_MSG=$'\n🚨 **[高危] 该节点已被 Google 判定为中国大陆 (送中)!**\n'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7. 组装情报级 Markdown 战报
|
||||||
|
# 提取本地运行态版本与生成时间戳
|
||||||
|
LOCAL_VER="${AGENT_VERSION:-未知}"
|
||||||
|
# [时区对齐] 深海声呐战报落款强制采用绝对 UTC 时间
|
||||||
|
CURRENT_TIME=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
# [体验修复] 探针返回的 IP 带有星号掩码,强制使用中枢下发的真实 IP 拼接,以防直达链接失效!
|
||||||
|
LINK_IP=$(echo "$PUBLIC_IP" | tr -d '[]')
|
||||||
|
|
||||||
|
REPORT="🎯 *IP-Sentinel 深海声呐报告*
|
||||||
|
📍 节点:\`${NODE_ALIAS}\`
|
||||||
|
🌐 地址:\`${IP_ADDR}\`${WARNING_MSG}
|
||||||
|
|
||||||
|
*🏢 物理身份与网络属性*
|
||||||
|
\`AS${ASN}\` | \`${ORG}\`
|
||||||
|
**定位:** \`${COUNTRY} - ${CITY}\`
|
||||||
|
**属性:** \`${IP_TYPE}\` | \`${USAGE_TYPE}\`
|
||||||
|
**探针:** ${IS_PROXY}
|
||||||
|
|
||||||
|
*🛡️ 欺诈雷达 (0为最优)*
|
||||||
|
• **Scamalytics:** \`${SCAM_SCORE}/100\`
|
||||||
|
• **AbuseIPDB:** \`${ABUSE_SCORE}/100\`
|
||||||
|
• **IPQS:** \`${IPQS_SCORE}/100\`
|
||||||
|
• **IP2Location:** \`${IP2L_SCORE}/100\`
|
||||||
|
• **IPAPI 风险率:** \`${FRAUD_RISK}\`
|
||||||
|
|
||||||
|
*🎬 核心业务解锁*
|
||||||
|
• **YouTube:** ${YT_STAT}
|
||||||
|
• **Netflix:** ${NF_STAT}
|
||||||
|
• **Disney+:** ${DP_STAT}
|
||||||
|
• **PrimeVideo:** ${APV_STAT}
|
||||||
|
• **TikTok:** ${TK_STAT}
|
||||||
|
• **ChatGPT:** ${GPT_STAT}
|
||||||
|
|
||||||
|
*✉️ 邮局与污染度*
|
||||||
|
• **25 端口出站:** ${P25_TEXT}
|
||||||
|
• **DNS 污染库:** 严重 \`${DNS_BLACK}\` | 轻微 \`${DNS_MARK}\`
|
||||||
|
|
||||||
|
_👉 [🔍 详细信用图谱直达 (Scamalytics)](https://scamalytics.com/ip/${LINK_IP})_
|
||||||
|
|
||||||
|
⏱️ \`${CURRENT_TIME}\` | ⚙️ \`v${LOCAL_VER}\`"
|
||||||
|
|
||||||
|
# [修复] 剥离显示层的 N/A,确保传给 Master 趋势数据库的是纯数字 (无效则记为0)
|
||||||
|
SAFE_SCAM_SCORE=$(echo "$SCAM_SCORE" | tr -cd '0-9')
|
||||||
|
[ -z "$SAFE_SCAM_SCORE" ] && SAFE_SCAM_SCORE="0"
|
||||||
|
|
||||||
|
# [v4.0.2 扩容] 提取 Google(基于YouTube) 和 ChatGPT 的原生状态
|
||||||
|
RAW_GOOG_STAT="${RAW_YT_REG:-$RAW_YT_STAT}"
|
||||||
|
[ -z "$RAW_GOOG_STAT" ] && RAW_GOOG_STAT="未知"
|
||||||
|
RAW_GPT_STAT=$(echo "$JSON_DATA" | jq -r '.Media.ChatGPT.Status // "未知"' 2>/dev/null)
|
||||||
|
|
||||||
|
# [修复] 废除会导致中文 UTF-8 字节被劈裂(产生乱码 )的 awk 暴力截断。
|
||||||
|
# 原始状态文本极短(如"解锁"、"屏蔽"、"US"),只需洗掉隐形换行符即可安全传输。
|
||||||
|
S_GOOG=$(echo "$RAW_GOOG_STAT" | tr -d '\n\r ')
|
||||||
|
S_NF=$(echo "$RAW_NF_STAT" | tr -d '\n\r ')
|
||||||
|
S_GPT=$(echo "$RAW_GPT_STAT" | tr -d '\n\r ')
|
||||||
|
CB_DATA="svq|${NODE_NAME}|${SAFE_SCAM_SCORE}|${S_GOOG}|${S_NF}|${S_GPT}"
|
||||||
|
|
||||||
|
# 8. 挂载内联键盘并直送指挥部
|
||||||
|
JSON_PAYLOAD=$(jq -n \
|
||||||
|
--arg cid "$CHAT_ID" \
|
||||||
|
--arg txt "$REPORT" \
|
||||||
|
--arg cb "$CB_DATA" \
|
||||||
|
--arg cb_manage "manage:${NODE_NAME}" \
|
||||||
|
'{
|
||||||
|
chat_id: $cid,
|
||||||
|
text: $txt,
|
||||||
|
parse_mode: "Markdown",
|
||||||
|
disable_web_page_preview: true,
|
||||||
|
reply_markup: {
|
||||||
|
inline_keyboard: [
|
||||||
|
[{text: "📥 将本次体检录入趋势库", callback_data: $cb}],
|
||||||
|
[{text: "⚙️ 调出该节点控制台", callback_data: $cb_manage}]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}')
|
||||||
|
|
||||||
|
curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD" >/dev/null
|
||||||
@@ -11,7 +11,7 @@ UA_FILE="${INSTALL_DIR}/data/user_agents.txt"
|
|||||||
# 你的 GitHub 仓库 Raw 数据直链前缀
|
# 你的 GitHub 仓库 Raw 数据直链前缀
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
# 临时改为私库地址用于测试
|
# 临时改为私库地址用于测试
|
||||||
# REPO_RAW_URL="https://git.94211762.xyz/hotyue/IP-Sentinel/raw/branch/main"
|
# REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/v3.6.2-rc"
|
||||||
|
|
||||||
# 1. 基础环境校验
|
# 1. 基础环境校验
|
||||||
[ ! -f "$CONFIG_FILE" ] && exit 1
|
[ ! -f "$CONFIG_FILE" ] && exit 1
|
||||||
@@ -45,7 +45,8 @@ fi
|
|||||||
log_msg() {
|
log_msg() {
|
||||||
local TYPE=$1
|
local TYPE=$1
|
||||||
local MSG=$2
|
local MSG=$2
|
||||||
local TIME=$(date "+%Y-%m-%d %H:%M:%S")
|
# [时区对齐] 强制无视本地时区,以绝对 UTC 时间生成日志时间戳
|
||||||
|
local TIME=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
||||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||||
local local_ver="${AGENT_VERSION:-未知}"
|
local local_ver="${AGENT_VERSION:-未知}"
|
||||||
|
|
||||||
@@ -99,14 +100,21 @@ CURL_BIND_OPT=""
|
|||||||
DYNAMIC_IP_PREF="-${IP_PREF:-4}" # 默认提取用户配置
|
DYNAMIC_IP_PREF="-${IP_PREF:-4}" # 默认提取用户配置
|
||||||
|
|
||||||
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
||||||
CURL_BIND_OPT="--interface $BIND_IP"
|
# [v3.6.3 容错层补丁] 探测物理网卡/虚拟 IP 存活状态
|
||||||
# 智能探测:带冒号为 V6,带点号为 V4
|
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||||
if [[ "$BIND_IP" == *":"* ]]; then
|
if ! ip addr show 2>/dev/null | grep -qw "$RAW_BIND_IP"; then
|
||||||
DYNAMIC_IP_PREF="-6"
|
log_msg "WARN " "检测到配置的出口 IP ($RAW_BIND_IP) 已丢失,自动降级为系统默认路由出网!"
|
||||||
log_msg "INFO " "底层路由锁定: 绑定 IPv6 出口及协议 ($BIND_IP)"
|
CURL_BIND_OPT=""
|
||||||
elif [[ "$BIND_IP" == *"."* ]]; then
|
else
|
||||||
DYNAMIC_IP_PREF="-4"
|
CURL_BIND_OPT="--interface $BIND_IP"
|
||||||
log_msg "INFO " "底层路由锁定: 绑定 IPv4 出口及协议 ($BIND_IP)"
|
# 智能探测:带冒号为 V6,带点号为 V4
|
||||||
|
if [[ "$BIND_IP" == *":"* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-6"
|
||||||
|
log_msg "INFO " "底层路由锁定: 绑定 IPv6 出口及协议 ($BIND_IP)"
|
||||||
|
elif [[ "$BIND_IP" == *"."* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-4"
|
||||||
|
log_msg "INFO " "底层路由锁定: 绑定 IPv4 出口及协议 ($BIND_IP)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ if [ ! -f "$CONFIG_FILE" ]; then
|
|||||||
fi
|
fi
|
||||||
source "$CONFIG_FILE"
|
source "$CONFIG_FILE"
|
||||||
|
|
||||||
|
# ================== [新增: 文件排他锁,防止并发重入引发内存雪崩] ==================
|
||||||
|
exec 200>"/tmp/ip_sentinel_runner.lock"
|
||||||
|
if ! flock -n 200; then
|
||||||
|
echo "[$(date)] ⚠️ 上一轮巡逻任务尚未结束,本次触发自动取消。" >> "$LOG_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
# ==================================================================================
|
||||||
|
|
||||||
# 2. 全局日志写入函数 (导出给子进程共享使用,v3.4.0 引入版本探针)
|
# 2. 全局日志写入函数 (导出给子进程共享使用,v3.4.0 引入版本探针)
|
||||||
log() {
|
log() {
|
||||||
local module=$1
|
local module=$1
|
||||||
@@ -25,14 +33,24 @@ log() {
|
|||||||
|
|
||||||
# 保证日志目录存在
|
# 保证日志目录存在
|
||||||
mkdir -p "${INSTALL_DIR}/logs"
|
mkdir -p "${INSTALL_DIR}/logs"
|
||||||
|
|
||||||
# 日志格式注入 [版本号] 追踪标识
|
# 日志格式注入 [版本号] 追踪标识
|
||||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [v%-5s] [%-5s] [%-7s] [%s] %s\n" "$local_ver" "$level" "$module" "$REGION_CODE" "$msg" >> "$LOG_FILE"
|
local core_msg=$(printf "[v%-5s] [%-5s] [%-7s] [%s] %s" "$local_ver" "$level" "$module" "$REGION_CODE" "$msg")
|
||||||
|
echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] $core_msg" >> "$LOG_FILE"
|
||||||
|
|
||||||
|
# 强制推送到 Systemd Journal (如果系统支持)
|
||||||
|
if command -v logger >/dev/null 2>&1; then
|
||||||
|
logger -t ip-sentinel "$core_msg"
|
||||||
|
else
|
||||||
|
# 降级输出到 stdout,让 Systemd 捕获
|
||||||
|
echo "$core_msg"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
export -f log
|
export -f log
|
||||||
export CONFIG_FILE INSTALL_DIR
|
export CONFIG_FILE INSTALL_DIR
|
||||||
|
|
||||||
# 3. 防僵尸网络特征 (Cron Jitter) - 核心隐蔽逻辑
|
# 3. 防僵尸网络特征 (Cron Jitter) - 核心隐蔽逻辑
|
||||||
# 配合每 30 分钟的调度周期,将随机休眠控制在 0 到 180 秒内,彻底打散全球并发请求
|
# 配合每 20 分钟的调度周期,将随机休眠控制在 0 到 180 秒内,彻底打散全球并发请求
|
||||||
if [ -t 1 ]; then
|
if [ -t 1 ]; then
|
||||||
log "SYSTEM" "INFO " "💻 检测到人工终端干预,跳过静默休眠,立即执行任务!"
|
log "SYSTEM" "INFO " "💻 检测到人工终端干预,跳过静默休眠,立即执行任务!"
|
||||||
else
|
else
|
||||||
@@ -73,7 +91,8 @@ fi
|
|||||||
if [ -n "$TARGET_MOD" ] && [ -x "${INSTALL_DIR}/core/${TARGET_MOD}" ]; then
|
if [ -n "$TARGET_MOD" ] && [ -x "${INSTALL_DIR}/core/${TARGET_MOD}" ]; then
|
||||||
log "SYSTEM" "INFO" "命中触发条件,加载并执行子模块: ${MOD_NAME}"
|
log "SYSTEM" "INFO" "命中触发条件,加载并执行子模块: ${MOD_NAME}"
|
||||||
# 核心降耗逻辑:使用 nice -n 19 赋予进程最低 CPU 优先级,绝不抢占 VPS 正常业务的资源
|
# 核心降耗逻辑:使用 nice -n 19 赋予进程最低 CPU 优先级,绝不抢占 VPS 正常业务的资源
|
||||||
nice -n 19 bash "${INSTALL_DIR}/core/${TARGET_MOD}"
|
# [安全修复] 注入 200>&-,强行关闭子进程对排他锁的继承权!防止子进程假死导致全局死锁
|
||||||
|
nice -n 19 bash "${INSTALL_DIR}/core/${TARGET_MOD}" 200>&-
|
||||||
else
|
else
|
||||||
log "SYSTEM" "ERROR" "配置了模块 ${MOD_NAME},但未找到对应的可执行脚本: ${TARGET_MOD}"
|
log "SYSTEM" "ERROR" "配置了模块 ${MOD_NAME},但未找到对应的可执行脚本: ${TARGET_MOD}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -18,21 +18,46 @@ if [ -z "$TG_TOKEN" ] || [ -z "$CHAT_ID" ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ================== [v4.0.8 核心: 防并发风暴与 60 秒冷却机制] ==================
|
||||||
|
LOCK_FILE="${INSTALL_DIR}/core/.report_lock"
|
||||||
|
if [ -f "$LOCK_FILE" ]; then
|
||||||
|
LAST_RUN=$(cat "$LOCK_FILE" 2>/dev/null)
|
||||||
|
NOW=$(date +%s)
|
||||||
|
# 校验 LAST_RUN 是否为有效数字,并比对 60 秒冷却期
|
||||||
|
if [[ "$LAST_RUN" =~ ^[0-9]+$ ]]; then
|
||||||
|
if [ $((NOW - LAST_RUN)) -lt 60 ]; then
|
||||||
|
echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] [v${AGENT_VERSION:-未知}] [WARN ] [Report ] [SYSTEM] ⚠️ 战报请求过于频繁,触发 60 秒防并发风暴拦截。" >> "${INSTALL_DIR}/logs/sentinel.log"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo $(date +%s) > "$LOCK_FILE"
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
# 2. 节点元数据抓取 (v3.2.2 协议自适应与多级容灾版)
|
# 2. 节点元数据抓取 (v3.2.2 协议自适应与多级容灾版)
|
||||||
# [v3.3.2 修复: 引入 IP 哈希防同名覆盖机制]
|
# [v3.5.2 核心: 引入双轨身份架构]
|
||||||
IP_HASH=$(echo "${PUBLIC_IP:-127.0.0.1}" | md5sum | cut -c 1-4 | tr 'a-z' 'A-Z')
|
if [ -z "$NODE_NAME" ]; then
|
||||||
NODE_NAME="$(hostname | cut -c 1-10)-${IP_HASH}"
|
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}"
|
||||||
|
fi
|
||||||
|
NODE_ALIAS="${NODE_ALIAS:-$NODE_NAME}"
|
||||||
|
|
||||||
# --- [防线 1: 底层路由锁定与协议自适应] ---
|
# --- [防线 1: 底层路由锁定与协议自适应] ---
|
||||||
CURL_BIND_OPT=""
|
CURL_BIND_OPT=""
|
||||||
DYNAMIC_IP_PREF="-${IP_PREF:-4}"
|
DYNAMIC_IP_PREF="-${IP_PREF:-4}"
|
||||||
|
|
||||||
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
if [[ -n "$BIND_IP" && "$BIND_IP" =~ ^[0-9a-fA-F:\.]+$ ]]; then
|
||||||
CURL_BIND_OPT="--interface $BIND_IP"
|
# [v3.6.3 容错层补丁] 探测物理网卡/虚拟 IP 存活状态
|
||||||
if [[ "$BIND_IP" == *":"* ]]; then
|
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||||
DYNAMIC_IP_PREF="-6"
|
if ! ip addr show 2>/dev/null | grep -qw "$RAW_BIND_IP"; then
|
||||||
elif [[ "$BIND_IP" == *"."* ]]; then
|
CURL_BIND_OPT=""
|
||||||
DYNAMIC_IP_PREF="-4"
|
else
|
||||||
|
CURL_BIND_OPT="--interface $BIND_IP"
|
||||||
|
if [[ "$BIND_IP" == *":"* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-6"
|
||||||
|
elif [[ "$BIND_IP" == *"."* ]]; then
|
||||||
|
DYNAMIC_IP_PREF="-4"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -83,17 +108,18 @@ case "$REGION_CODE" in
|
|||||||
"SG") FLAG="🇸🇬" ;;
|
"SG") FLAG="🇸🇬" ;;
|
||||||
"HK") FLAG="🇭🇰" ;;
|
"HK") FLAG="🇭🇰" ;;
|
||||||
"GB"|"UK") FLAG="🇬🇧" ;;
|
"GB"|"UK") FLAG="🇬🇧" ;;
|
||||||
|
"AU") FLAG="🇦🇺" ;;
|
||||||
*) FLAG="🌐" ;;
|
*) FLAG="🌐" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# 3. 截取过去 24 小时的日志
|
# 3. 截取过去 24 小时的日志 (每天72次轮询,保留最新 1000 行足以覆盖单日战报)
|
||||||
LOG_CONTENT=$(find "$LOG_FILE" -mtime -1 -exec cat {} \; 2>/dev/null)
|
LOG_CONTENT=$(tail -n 1000 "$LOG_FILE" 2>/dev/null)
|
||||||
|
|
||||||
if [ -z "$LOG_CONTENT" ]; then
|
if [ -z "$LOG_CONTENT" ]; then
|
||||||
read -r -d '' MSG <<EOT
|
read -r -d '' MSG <<EOT
|
||||||
🛑 **[IP-Sentinel] 告警:节点异常**
|
🛑 **[IP-Sentinel] 告警:节点异常**
|
||||||
----------------------------
|
----------------------------
|
||||||
📍 **节点名称**: \`${NODE_NAME}\`
|
📍 **节点名称**: \`${NODE_ALIAS}\`
|
||||||
⚠️ **警告**: 过去 24 小时无运行日志!
|
⚠️ **警告**: 过去 24 小时无运行日志!
|
||||||
🛠️ **建议**: 节点可能刚部署完毕,请在面板手动执行一次养护动作。
|
🛠️ **建议**: 节点可能刚部署完毕,请在面板手动执行一次养护动作。
|
||||||
EOT
|
EOT
|
||||||
@@ -111,7 +137,7 @@ else
|
|||||||
# 开始组装战报头部
|
# 开始组装战报头部
|
||||||
MSG="📊 **IP-Sentinel 每日简报 (${FLAG} ${REGION_NAME})**
|
MSG="📊 **IP-Sentinel 每日简报 (${FLAG} ${REGION_NAME})**
|
||||||
----------------------------
|
----------------------------
|
||||||
📍 **节点名称**: \`${NODE_NAME}\`
|
📍 **节点名称**: \`${NODE_ALIAS}\`
|
||||||
📡 **出口 IP**: \`${CURRENT_IP}\`
|
📡 **出口 IP**: \`${CURRENT_IP}\`
|
||||||
🛡️ **IP 属性**: ${IP_TYPE}"
|
🛡️ **IP 属性**: ${IP_TYPE}"
|
||||||
|
|
||||||
@@ -154,7 +180,7 @@ else
|
|||||||
MSG="$MSG
|
MSG="$MSG
|
||||||
|
|
||||||
🕒 **最近执行快照 [${LAST_MOD:-"System"}]:**
|
🕒 **最近执行快照 [${LAST_MOD:-"System"}]:**
|
||||||
时间: ${LAST_TIME:-"暂无数据"}
|
时间: ${LAST_TIME:-"暂无数据"} (节点本地)
|
||||||
结论: ${LAST_SCORE:-"暂无数据"}"
|
结论: ${LAST_SCORE:-"暂无数据"}"
|
||||||
|
|
||||||
fi
|
fi
|
||||||
@@ -164,15 +190,18 @@ fi
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
# 从配置文件提取当前本地版本,若无则默认为未知
|
# 从配置文件提取当前本地版本,若无则默认为未知
|
||||||
LOCAL_VER="${AGENT_VERSION:-未知}"
|
LOCAL_VER="${AGENT_VERSION:-未知}"
|
||||||
|
# [时区对齐] 强制获取当前绝对 UTC 时间,作为全局统一的战报落款
|
||||||
|
REPORT_UTC_TIME=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
||||||
|
|
||||||
# 极轻量级探针: 抓取 GitHub 云端的 version.txt (超时 3 秒)
|
# 极轻量级探针: 抓取 GitHub 云端的 version.txt (超时 3 秒,KV解析法)
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
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:]')
|
REMOTE_VER=$(curl -s -m 3 "${REPO_RAW_URL}/version.txt" | grep "^AGENT_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]')
|
||||||
|
|
||||||
# 构建底部引擎状态块
|
# 构建底部引擎状态块
|
||||||
MSG="$MSG
|
MSG="$MSG
|
||||||
----------------------------
|
----------------------------
|
||||||
🛡️ **系统引擎状态**
|
🛡️ **系统引擎状态**
|
||||||
|
⏱️ 战报生成: \`${REPORT_UTC_TIME}\`
|
||||||
当前运行版本: \`v${LOCAL_VER}\`"
|
当前运行版本: \`v${LOCAL_VER}\`"
|
||||||
|
|
||||||
# 比对逻辑:如果成功抓到了远端版本,且和本地不一样
|
# 比对逻辑:如果成功抓到了远端版本,且和本地不一样
|
||||||
@@ -190,11 +219,24 @@ else
|
|||||||
💡 *哨兵正在后台默默守护您的资产。*"
|
💡 *哨兵正在后台默默守护您的资产。*"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 5. 调用 API 推送 (接入安全网关)
|
# 5. 调用 API 推送 (接入安全网关,挂载交互式控制台按钮)
|
||||||
|
JSON_PAYLOAD=$(jq -n \
|
||||||
|
--arg cid "$CHAT_ID" \
|
||||||
|
--arg txt "$MSG" \
|
||||||
|
--arg cb "manage:${NODE_NAME}" \
|
||||||
|
'{
|
||||||
|
chat_id: $cid,
|
||||||
|
text: $txt,
|
||||||
|
parse_mode: "Markdown",
|
||||||
|
disable_web_page_preview: true,
|
||||||
|
reply_markup: {
|
||||||
|
inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]
|
||||||
|
}
|
||||||
|
}')
|
||||||
|
|
||||||
RESPONSE=$(curl -s -m 10 -X POST "${TG_API_URL}" \
|
RESPONSE=$(curl -s -m 10 -X POST "${TG_API_URL}" \
|
||||||
-d "chat_id=${CHAT_ID}" \
|
-H "Content-Type: application/json" \
|
||||||
-d "text=${MSG}" \
|
-d "$JSON_PAYLOAD")
|
||||||
-d "parse_mode=Markdown")
|
|
||||||
|
|
||||||
if [[ "$RESPONSE" != *"\"ok\":true"* ]]; then
|
if [[ "$RESPONSE" != *"\"ok\":true"* ]]; then
|
||||||
echo "❌ 战报发送失败!API 响应: $RESPONSE" >> "${INSTALL_DIR}/logs/error.log"
|
echo "❌ 战报发送失败!API 响应: $RESPONSE" >> "${INSTALL_DIR}/logs/error.log"
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# 脚本名称: uninstall.sh (IP-Sentinel 一键卸载脚本 - 动态锚点版)
|
# 脚本名称: uninstall.sh (IP-Sentinel 一键卸载脚本 - 动态锚点版)
|
||||||
# 核心功能: 无痕清理守护进程、定时任务、运行目录及临时缓存
|
# 核心功能: 无痕清理守护进程、定时任务、运行目录及临时缓存
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 🛑 核心权限防线: 检查是否以 root 权限运行
|
||||||
|
# ==========================================================
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "\033[31m❌ 权限被拒绝: 卸载 IP-Sentinel 需要最高系统权限。\033[0m"
|
||||||
|
echo -e "💡 请切换到 root 用户 (执行 su root 或 sudo -i) 后重新运行指令。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
INSTALL_DIR="/opt/ip_sentinel"
|
INSTALL_DIR="/opt/ip_sentinel"
|
||||||
|
|
||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
@@ -18,13 +26,33 @@ if [ -f "$CONFIG_FILE" ]; then
|
|||||||
fi
|
fi
|
||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
|
|
||||||
# 1. 停止运行中的守护进程与主控模块 (涵盖所有历史版本进程)
|
# 1. 停止并删除 Systemd 服务 (适配新架构)
|
||||||
echo "[1/3] 正在终止后台守护进程与所有养护任务..."
|
echo "[1/4] 正在停止并删除 Systemd 服务..."
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "💡 检测到 Systemd 环境,正在抹除 Systemd 服务单元..."
|
||||||
|
# [防死锁与走火修复] 先发送 SIGKILL 瞬间抹杀常驻守护进程,防止卡死或触发遗言
|
||||||
|
systemctl kill --signal=SIGKILL ip-sentinel-agent-daemon.service >/dev/null 2>&1 || true
|
||||||
|
systemctl disable --now ip-sentinel-runner.service ip-sentinel-runner.timer \
|
||||||
|
ip-sentinel-updater.service ip-sentinel-updater.timer \
|
||||||
|
ip-sentinel-report.service ip-sentinel-report.timer \
|
||||||
|
ip-sentinel-agent-daemon.service >/dev/null 2>&1
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-runner.service
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-runner.timer
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-updater.service
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-updater.timer
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-report.service
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-report.timer
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-agent-daemon.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl reset-failed
|
||||||
|
else
|
||||||
|
echo "💡 未检测到 Systemd,跳过此步骤..."
|
||||||
|
fi
|
||||||
|
|
||||||
# 使用 pkill 替代传统的 pgrep | xargs,指令更短、容错率更高
|
# 2. 停止运行中的守护进程与主控模块 (兜底清理老版进程)
|
||||||
|
echo "[2/4] 正在终止后台守护进程与所有养护任务..."
|
||||||
pkill -9 -f "tg_daemon.sh" >/dev/null 2>&1
|
pkill -9 -f "tg_daemon.sh" >/dev/null 2>&1
|
||||||
pkill -9 -f "agent_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 "python3.*webhook.py" >/dev/null 2>&1
|
||||||
pkill -9 -f "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 "runner.sh" >/dev/null 2>&1
|
||||||
@@ -32,25 +60,38 @@ pkill -9 -f "updater.sh" >/dev/null 2>&1
|
|||||||
pkill -9 -f "tg_report.sh" >/dev/null 2>&1
|
pkill -9 -f "tg_report.sh" >/dev/null 2>&1
|
||||||
pkill -9 -f "mod_google.sh" >/dev/null 2>&1
|
pkill -9 -f "mod_google.sh" >/dev/null 2>&1
|
||||||
pkill -9 -f "mod_trust.sh" >/dev/null 2>&1
|
pkill -9 -f "mod_trust.sh" >/dev/null 2>&1
|
||||||
|
pkill -9 -f "sentinel_scheduler.sh" >/dev/null 2>&1
|
||||||
|
|
||||||
# 2. 清除系统定时任务 (Cron)
|
# 3. 清除系统定时任务 (Cron)
|
||||||
echo "[2/3] 正在清理系统定时任务 (Cron)..."
|
echo "[3/4] 正在清理系统定时任务 (Cron)..."
|
||||||
if crontab -l >/dev/null 2>&1; then
|
# [终极安全防御] 直接使用管道流过滤并覆盖,不产生任何 /tmp 落地文件,杜绝劫持提权
|
||||||
crontab -l | grep -v "ip_sentinel" > /tmp/cron_backup
|
crontab -l 2>/dev/null | grep -v "ip_sentinel" | crontab - >/dev/null 2>&1 || true
|
||||||
crontab /tmp/cron_backup
|
|
||||||
rm -f /tmp/cron_backup
|
# ==========================================
|
||||||
|
# 🛑 [物理抹除] 彻底扫除 Alpine 系统的底层残留与双路径文件
|
||||||
|
# ==========================================
|
||||||
|
for CRON_FILE in "/var/spool/cron/crontabs/root" "/etc/crontabs/root"; do
|
||||||
|
if [ -f "$CRON_FILE" ]; then
|
||||||
|
grep -v "ip_sentinel" "$CRON_FILE" > "${CRON_FILE}.tmp" 2>/dev/null || true
|
||||||
|
cat "${CRON_FILE}.tmp" > "$CRON_FILE" 2>/dev/null || true
|
||||||
|
rm -f "${CRON_FILE}.tmp" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# 清理 OpenRC 开机启动项
|
||||||
|
rm -f /etc/local.d/ip_sentinel.start 2>/dev/null
|
||||||
|
rm -f /etc/local.d/ip_sentinel_scheduler.start 2>/dev/null
|
||||||
|
|
||||||
|
# 清理极端环境写在 /etc/profile 里的兜底启动项
|
||||||
|
if grep -q "sentinel_scheduler.sh" /etc/profile 2>/dev/null; then
|
||||||
|
sed -i '/sentinel_scheduler\.sh/d' /etc/profile 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. 删除所有文件、日志与临时缓存
|
# 4. 删除所有文件、日志与临时缓存
|
||||||
echo "[3/3] 正在抹除核心程序、配置文件与系统痕迹..."
|
echo "[4/4] 正在抹除核心程序、配置文件与系统痕迹..."
|
||||||
if [ -d "$INSTALL_DIR" ]; then
|
if [ -d "$INSTALL_DIR" ]; then
|
||||||
rm -rf "$INSTALL_DIR"
|
rm -rf "$INSTALL_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 拔除 /tmp 目录下的所有更新下载临时文件和 V1/V2 遗留的偏移量记录
|
|
||||||
rm -f /tmp/ip_sentinel_*.txt
|
|
||||||
rm -f /tmp/ip_sentinel_*.json
|
|
||||||
|
|
||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
echo "✅ 卸载彻底完成!IP-Sentinel 已从您的系统中无痕移除。"
|
echo "✅ 卸载彻底完成!IP-Sentinel 已从您的系统中无痕移除。"
|
||||||
echo "💡 提示:如果安装时在防火墙放行了 Webhook 随机端口,请您按需手动关闭。"
|
echo "💡 提示:如果安装时在防火墙放行了 Webhook 随机端口,请您按需手动关闭。"
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ UA_TIME_FILE="${INSTALL_DIR}/core/.ua_last_update"
|
|||||||
|
|
||||||
# GitHub 仓库 Raw 数据直链前缀
|
# GitHub 仓库 Raw 数据直链前缀
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
|
# 临时改为开发地址用于测试
|
||||||
|
# REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/v3.6.2-rc"
|
||||||
|
|
||||||
# 1. 加载本地冷数据配置
|
# 1. 加载本地冷数据配置
|
||||||
if [ ! -f "$CONFIG_FILE" ]; then
|
if [ ! -f "$CONFIG_FILE" ]; then
|
||||||
@@ -23,9 +25,21 @@ log() {
|
|||||||
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
# [v3.4.0 核心] 提取当前配置中的版本锚点
|
||||||
local local_ver="${AGENT_VERSION:-未知}"
|
local local_ver="${AGENT_VERSION:-未知}"
|
||||||
|
|
||||||
|
# 保证日志目录存在
|
||||||
mkdir -p "${INSTALL_DIR}/logs"
|
mkdir -p "${INSTALL_DIR}/logs"
|
||||||
|
|
||||||
# 日志格式注入 [版本号] 追踪标识
|
# 日志格式注入 [版本号] 追踪标识
|
||||||
printf "[$(date '+%Y-%m-%d %H:%M:%S')] [v%-5s] [%-5s] [%-7s] [%s] %s\n" "$local_ver" "$2" "$1" "$REGION_CODE" "$3" >> "$LOG_FILE"
|
local core_msg=$(printf "[v%-5s] [%-5s] [%-7s] [%s] %s" "$local_ver" "$2" "$1" "$REGION_CODE" "$3")
|
||||||
|
# [时区对齐] 强制无视本地时区,以绝对 UTC 时间写入日志
|
||||||
|
echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] $core_msg" >> "$LOG_FILE"
|
||||||
|
|
||||||
|
# 强制推送到 Systemd Journal (如果系统支持)
|
||||||
|
if command -v logger >/dev/null 2>&1; then
|
||||||
|
logger -t ip-sentinel "$core_msg"
|
||||||
|
else
|
||||||
|
# 降级输出到 stdout,让 Systemd 捕获
|
||||||
|
echo "$core_msg"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
log "Updater" "INFO " "========== 触发后台静默 OTA 热数据更新 =========="
|
log "Updater" "INFO " "========== 触发后台静默 OTA 热数据更新 =========="
|
||||||
@@ -40,7 +54,12 @@ CURL_CMD="curl -${IP_PREF:-4} -sL"
|
|||||||
if [ -n "$BIND_IP" ]; then
|
if [ -n "$BIND_IP" ]; then
|
||||||
# curl 的 --interface 参数不支持带方括号的 IPv6 地址,必须强行脱壳
|
# curl 的 --interface 参数不支持带方括号的 IPv6 地址,必须强行脱壳
|
||||||
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
RAW_BIND_IP=$(echo "$BIND_IP" | tr -d '[]')
|
||||||
CURL_CMD="$CURL_CMD --interface $RAW_BIND_IP"
|
# [v3.6.3 容错层补丁] 探测网卡存活状态,防止 IP 漂移导致永久断网
|
||||||
|
if ! ip addr show 2>/dev/null | grep -qw "$RAW_BIND_IP"; then
|
||||||
|
log "Updater" "WARN " "检测到绑定的出口 IP ($RAW_BIND_IP) 已丢失,自动退回默认路由!"
|
||||||
|
else
|
||||||
|
CURL_CMD="$CURL_CMD --interface $RAW_BIND_IP"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
@@ -115,6 +134,22 @@ if [ -n "$REGION_JSON_FILE" ] && [ -f "$REGION_JSON_FILE" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 5.5. 容灾更新深海声呐底层探针 (彻底消除第三方 RCE 依赖)
|
||||||
|
# ==========================================================
|
||||||
|
TMP_PROBE="/tmp/ip_sentinel_probe.sh"
|
||||||
|
$CURL_CMD "https://raw.githubusercontent.com/xykt/IPQuality/main/ip.sh" -o "$TMP_PROBE"
|
||||||
|
|
||||||
|
# 🛡️ 供应链防毒:验证脚本内是否包含原作者特有签名,防止被墙重定向为 HTML
|
||||||
|
if [ -s "$TMP_PROBE" ] && grep -q "xykt" "$TMP_PROBE" 2>/dev/null; then
|
||||||
|
mv "$TMP_PROBE" "${INSTALL_DIR}/core/ip_probe.sh"
|
||||||
|
chmod +x "${INSTALL_DIR}/core/ip_probe.sh"
|
||||||
|
log "Updater" "INFO " "✅ 深海声呐底层探针 (ip_probe.sh) 源文件安全对齐"
|
||||||
|
else
|
||||||
|
log "Updater" "WARN " "❌ 探针源文件拉取受损或遭投毒劫持,已触发防砖机制,保留本地旧版本"
|
||||||
|
rm -f "$TMP_PROBE" 2>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# 6. 日志防满瘦身机制 (保留最近 2000 行)
|
# 6. 日志防满瘦身机制 (保留最近 2000 行)
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|||||||
200
data/keywords/kw_AU.txt
Normal file
200
data/keywords/kw_AU.txt
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
jarome luai png chiefs
|
||||||
|
gauche
|
||||||
|
keith urban daughter instagram unfollow
|
||||||
|
sarah ferguson
|
||||||
|
one championship
|
||||||
|
parafield airport
|
||||||
|
ai bubble
|
||||||
|
tony burke
|
||||||
|
professor richard scolyer
|
||||||
|
san antonio spurs vs portland trail blazers match player stats
|
||||||
|
prince harry working royal
|
||||||
|
retirement
|
||||||
|
rebate
|
||||||
|
denver nuggets
|
||||||
|
rudy gobert
|
||||||
|
driver's license
|
||||||
|
nuggets
|
||||||
|
jessica biel justin timberlake ultimatum
|
||||||
|
qatar
|
||||||
|
thales
|
||||||
|
destroyer
|
||||||
|
nrl news latrell mitchell
|
||||||
|
heavy snow warning
|
||||||
|
the rookie dead ringer
|
||||||
|
ducks vs oilers
|
||||||
|
ivan soldo
|
||||||
|
uae vs oman
|
||||||
|
cheryl hines
|
||||||
|
deandre ayton
|
||||||
|
real estate market
|
||||||
|
weather brisbane
|
||||||
|
raptors vs cavaliers
|
||||||
|
galatasaray
|
||||||
|
multan sultans vs islamabad united
|
||||||
|
galatasaray vs fenerbahçe
|
||||||
|
torino vs inter
|
||||||
|
hearts fc
|
||||||
|
scottish premier league
|
||||||
|
mohsin khan
|
||||||
|
angkrish raghuvanshi
|
||||||
|
psl
|
||||||
|
magic vs pistons
|
||||||
|
celtic fc
|
||||||
|
peshawar zalmi vs lahore qalandars
|
||||||
|
angers vs psg
|
||||||
|
la liga
|
||||||
|
prem
|
||||||
|
premier league table
|
||||||
|
epl fixtures
|
||||||
|
premier league games
|
||||||
|
alex de minaur
|
||||||
|
sunderland vs nottm forest
|
||||||
|
real betis vs real madrid
|
||||||
|
sai sudharsan
|
||||||
|
jannik sinner
|
||||||
|
gt vs rcb
|
||||||
|
amd stock
|
||||||
|
carey mulligan
|
||||||
|
jermaine jackson
|
||||||
|
hulk hogan
|
||||||
|
coles
|
||||||
|
elon musk
|
||||||
|
ben roberts-smith
|
||||||
|
ig
|
||||||
|
danish malewar
|
||||||
|
assassin's creed black flag resynced
|
||||||
|
sarfaraz khan
|
||||||
|
kartik sharma
|
||||||
|
instagram stories not working
|
||||||
|
meningococcal b
|
||||||
|
sundaresh menon
|
||||||
|
thunder vs suns
|
||||||
|
cade cunningham
|
||||||
|
real salt lake vs inter miami
|
||||||
|
pope francis
|
||||||
|
camera
|
||||||
|
anzac
|
||||||
|
teams
|
||||||
|
kids news
|
||||||
|
bonds
|
||||||
|
hung cao
|
||||||
|
classroom
|
||||||
|
michael jackson biopic movie
|
||||||
|
india women vs south africa women
|
||||||
|
nato
|
||||||
|
bayern munich
|
||||||
|
barcelona vs celta vigo
|
||||||
|
bournemouth vs leeds
|
||||||
|
leverkusen vs bayern
|
||||||
|
burnley vs man city
|
||||||
|
elche vs atlético madrid
|
||||||
|
lsg vs rr
|
||||||
|
pakistan super league
|
||||||
|
kyle sandilands alleged rant jackie o
|
||||||
|
carrie bickmore
|
||||||
|
adam levine
|
||||||
|
alexandra eala
|
||||||
|
tubi
|
||||||
|
charles melton
|
||||||
|
nuclear weapon
|
||||||
|
janet jackson
|
||||||
|
justin bieber australia tour
|
||||||
|
fleche wallonne 2026
|
||||||
|
ange postecoglou
|
||||||
|
john hattie
|
||||||
|
airbus a380
|
||||||
|
real madrid vs alavés
|
||||||
|
brighton vs chelsea
|
||||||
|
woolworth
|
||||||
|
nitish rana
|
||||||
|
lyrid meteor shower
|
||||||
|
世界地球日
|
||||||
|
youth gang
|
||||||
|
earth day
|
||||||
|
crystal palace vs west ham
|
||||||
|
d4vd
|
||||||
|
mi vs gt
|
||||||
|
perth weather
|
||||||
|
elijah hollands carlton football club
|
||||||
|
fair work commission fuel
|
||||||
|
vanguard
|
||||||
|
sydney sweeney
|
||||||
|
cailee spaeny
|
||||||
|
psg vs lyon
|
||||||
|
sporting vs benfica
|
||||||
|
celtics vs 76ers
|
||||||
|
bundesliga
|
||||||
|
pl
|
||||||
|
afc cup
|
||||||
|
mars rover
|
||||||
|
bayern vs vfb stuttgart
|
||||||
|
bom radar
|
||||||
|
sydney weather
|
||||||
|
melbourne weather
|
||||||
|
brisbane weather
|
||||||
|
adelaide weather
|
||||||
|
myGov login
|
||||||
|
news.com.au
|
||||||
|
abc news
|
||||||
|
nrl ladder
|
||||||
|
afl scores
|
||||||
|
afl fixture
|
||||||
|
matildas
|
||||||
|
sam kerr
|
||||||
|
bunnings opening hours
|
||||||
|
coles catalogue
|
||||||
|
woolies specials
|
||||||
|
qantas
|
||||||
|
virgin australia
|
||||||
|
jetstar flights
|
||||||
|
commbank
|
||||||
|
asx 200
|
||||||
|
sydney morning herald
|
||||||
|
the age
|
||||||
|
ticketek
|
||||||
|
ticketmaster
|
||||||
|
opal card top up
|
||||||
|
myki top up
|
||||||
|
translink timetable
|
||||||
|
transperth journey planner
|
||||||
|
adelaide metro
|
||||||
|
adelaide 500
|
||||||
|
adelaide crows
|
||||||
|
port adelaide
|
||||||
|
penrith panthers
|
||||||
|
brisbane broncos
|
||||||
|
collingwood fc
|
||||||
|
sydney swans
|
||||||
|
west coast eagles
|
||||||
|
fremantle dockers
|
||||||
|
canberra raiders
|
||||||
|
mcg events
|
||||||
|
optus stadium
|
||||||
|
the gabba
|
||||||
|
state of origin
|
||||||
|
australian open
|
||||||
|
melbourne cup
|
||||||
|
masterchef australia
|
||||||
|
mafs australia
|
||||||
|
petrol prices near me
|
||||||
|
australia post tracking
|
||||||
|
service nsw login
|
||||||
|
vicroads
|
||||||
|
queensland health
|
||||||
|
medicare
|
||||||
|
ato
|
||||||
|
jb hi-fi
|
||||||
|
kmart
|
||||||
|
amazon.com.au
|
||||||
|
vivid sydney
|
||||||
|
mona hobart
|
||||||
|
dark mofo
|
||||||
|
floriade canberra
|
||||||
|
rottnest island ferry
|
||||||
|
sydney airport arrivals
|
||||||
|
rba interest rate
|
||||||
|
nsw school holidays
|
||||||
|
qld school holidays
|
||||||
|
wa school holidays
|
||||||
|
m4 traffic updates
|
||||||
@@ -1,3 +1,188 @@
|
|||||||
|
danielle smith
|
||||||
|
workday
|
||||||
|
jermaine jackson
|
||||||
|
prada
|
||||||
|
next oilers game
|
||||||
|
anaheim ducks coach
|
||||||
|
dhurandhar 2
|
||||||
|
bchl
|
||||||
|
from tv series
|
||||||
|
whl
|
||||||
|
shea theodore
|
||||||
|
nikola jokić
|
||||||
|
mark stone
|
||||||
|
naz reid
|
||||||
|
cameron johnson
|
||||||
|
dea
|
||||||
|
dylan guenther
|
||||||
|
jamal murray
|
||||||
|
euphoria cast
|
||||||
|
mlb bo bichette
|
||||||
|
明天的天氣
|
||||||
|
edmonton news
|
||||||
|
radko gudas
|
||||||
|
oil
|
||||||
|
jeffrey viel
|
||||||
|
boat
|
||||||
|
joel quenneville
|
||||||
|
evan bouchard
|
||||||
|
jada wallace
|
||||||
|
oilers
|
||||||
|
boston bruins
|
||||||
|
patrick corbin
|
||||||
|
avs vs sporting
|
||||||
|
peyton krebs
|
||||||
|
elena rybakina
|
||||||
|
shane doan
|
||||||
|
ja'kobe walter
|
||||||
|
mitch marner
|
||||||
|
radio-canada
|
||||||
|
golf
|
||||||
|
hurricanes vs senators
|
||||||
|
al ahli
|
||||||
|
the white house
|
||||||
|
turkish airlines
|
||||||
|
fa cup games
|
||||||
|
atlético madrid vs athletic club
|
||||||
|
tyree wilson
|
||||||
|
monic néron
|
||||||
|
nvidia
|
||||||
|
aryna sabalenka
|
||||||
|
lpga leaderboard
|
||||||
|
randy travis
|
||||||
|
execution by firing squad
|
||||||
|
nelly korda
|
||||||
|
leicester city vs millwall
|
||||||
|
asteroid
|
||||||
|
sunderland vs nottm forest
|
||||||
|
real betis vs real madrid
|
||||||
|
betis – real madrid
|
||||||
|
napoli vs cremonese
|
||||||
|
gta 6
|
||||||
|
japon
|
||||||
|
padres vs rockies
|
||||||
|
guide de la révolution de l'iran
|
||||||
|
casa pia vs braga
|
||||||
|
denaturalization
|
||||||
|
ocean
|
||||||
|
alberta referendum
|
||||||
|
vfb stuttgart vs sc freiburg
|
||||||
|
gpt 5.5
|
||||||
|
noah cates
|
||||||
|
pwhl scores
|
||||||
|
hank idsinga
|
||||||
|
karoline leavitt
|
||||||
|
ottawa charge
|
||||||
|
million dollar secret
|
||||||
|
white sox vs diamondbacks
|
||||||
|
suns vs thunder
|
||||||
|
stars vs wild
|
||||||
|
jaafar jackson
|
||||||
|
airport
|
||||||
|
grand theft auto vi
|
||||||
|
pentagone
|
||||||
|
etats unis
|
||||||
|
monette farms news
|
||||||
|
jose soriano
|
||||||
|
jon cooper
|
||||||
|
barcelona vs celta vigo
|
||||||
|
764
|
||||||
|
david scott
|
||||||
|
rodrigo duterte
|
||||||
|
u18 world championship
|
||||||
|
zara tindall
|
||||||
|
graham platner
|
||||||
|
lsg vs rr
|
||||||
|
nikki glaser
|
||||||
|
global news edmonton
|
||||||
|
policier
|
||||||
|
nuclear weapon
|
||||||
|
motorcycle
|
||||||
|
msc francesca
|
||||||
|
poet stock
|
||||||
|
fifa tickets
|
||||||
|
7 jours
|
||||||
|
alexandra eala
|
||||||
|
earth
|
||||||
|
zara larsson
|
||||||
|
girona vs real betis
|
||||||
|
kevyn adams
|
||||||
|
ali khamenei
|
||||||
|
inter – côme
|
||||||
|
leicester city vs hull
|
||||||
|
fenerbahçe
|
||||||
|
françois bonnardel
|
||||||
|
missile
|
||||||
|
real madrid vs alavés
|
||||||
|
vrabel and russini photos
|
||||||
|
will trent
|
||||||
|
ibm
|
||||||
|
lecce vs fiorentina
|
||||||
|
celeste rivas hernandez
|
||||||
|
abhishek bachchan
|
||||||
|
national guard of the united states
|
||||||
|
triathlon
|
||||||
|
vincent trocheck
|
||||||
|
benyamin netanyahou
|
||||||
|
kings vs avalanche
|
||||||
|
crème solaire
|
||||||
|
trabzonspor vs istanbul başakşehir
|
||||||
|
indigenous rights
|
||||||
|
meghan, duchess of sussex
|
||||||
|
gwyneth paltrow
|
||||||
|
toronto gas prices
|
||||||
|
président
|
||||||
|
mets vs cubs
|
||||||
|
matt fitzpatrick
|
||||||
|
sénateurs – hurricanes
|
||||||
|
senators vs hurricanes
|
||||||
|
man utd
|
||||||
|
spurs
|
||||||
|
evan mobley
|
||||||
|
chelsea vs man united
|
||||||
|
atlético madrid vs real sociedad
|
||||||
|
roma vs atalanta
|
||||||
|
cf montreal
|
||||||
|
jakob poeltl
|
||||||
|
ukraine
|
||||||
|
contrôle routier québec
|
||||||
|
bachelorette 2026
|
||||||
|
lens – toulouse
|
||||||
|
arber xhekaj
|
||||||
|
leylah fernandez
|
||||||
|
anthropic
|
||||||
|
paige wwe
|
||||||
|
inter – cagliari
|
||||||
|
carrie ann inaba
|
||||||
|
syria
|
||||||
|
highway hotline sk
|
||||||
|
real betis vs braga
|
||||||
|
vincent bolloré
|
||||||
|
europa conference league
|
||||||
|
resident alien
|
||||||
|
battlefield 6
|
||||||
|
aston villa vs bologna
|
||||||
|
nottm forest vs porto
|
||||||
|
soccer
|
||||||
|
lamour est dans le pré
|
||||||
|
luis suárez
|
||||||
|
listeria
|
||||||
|
strc
|
||||||
|
bayern
|
||||||
|
arda güler
|
||||||
|
aleksandar pavlović
|
||||||
|
kooora
|
||||||
|
yalla kora
|
||||||
|
ina garten
|
||||||
|
jordan goodwin
|
||||||
|
jerami grant
|
||||||
|
jimmy snuggerud
|
||||||
|
clav
|
||||||
|
bts
|
||||||
|
zach galifianakis
|
||||||
|
billy crystal
|
||||||
|
club américa vs nashville
|
||||||
|
allison williams
|
||||||
CBC News
|
CBC News
|
||||||
Canada.ca
|
Canada.ca
|
||||||
Toronto Weather
|
Toronto Weather
|
||||||
|
|||||||
@@ -1,3 +1,187 @@
|
|||||||
|
swr aktuell baden-württemberg
|
||||||
|
wetter ulm
|
||||||
|
rettungshubschrauber
|
||||||
|
lebensmittelwarnung.de
|
||||||
|
julia ruhs
|
||||||
|
vw id polo
|
||||||
|
warburg
|
||||||
|
elon musk
|
||||||
|
diablo 4 warlock build
|
||||||
|
wirtschaft
|
||||||
|
фридрих мерц
|
||||||
|
zdf-fernsehgarten
|
||||||
|
halberstadt
|
||||||
|
cathie wood
|
||||||
|
fabian güstrow
|
||||||
|
spencer jones
|
||||||
|
jean alesi
|
||||||
|
hilary duff
|
||||||
|
nhl playoffs
|
||||||
|
msci
|
||||||
|
1. mai
|
||||||
|
ronnie o’sullivan
|
||||||
|
loris karius
|
||||||
|
koningsdag 2026
|
||||||
|
ryan reynolds
|
||||||
|
julia stiles
|
||||||
|
saïd el mala
|
||||||
|
tag der arbeit
|
||||||
|
gesundheitspolitik
|
||||||
|
der bergdoktor
|
||||||
|
bulgarien
|
||||||
|
george clooney
|
||||||
|
jork
|
||||||
|
star citizen
|
||||||
|
donau
|
||||||
|
krassnitzer harald
|
||||||
|
buxtehude
|
||||||
|
chernobyl
|
||||||
|
avs – sporting
|
||||||
|
running point
|
||||||
|
darmstadt
|
||||||
|
dahoam is dahoam
|
||||||
|
أتلتيكو مدريد ضد أتلتيك بيلباو
|
||||||
|
atlético madryt – ath. bilbao
|
||||||
|
portugal
|
||||||
|
erling haaland
|
||||||
|
galatasaray fenerbahce
|
||||||
|
anna carina woitschack
|
||||||
|
nord bei nordwest
|
||||||
|
wil wheaton
|
||||||
|
christian lindner
|
||||||
|
kevin costner
|
||||||
|
samu haber
|
||||||
|
gillian anderson
|
||||||
|
peggy jerofke
|
||||||
|
rafael jódar
|
||||||
|
ernie dosio
|
||||||
|
bibi heinicke
|
||||||
|
denia
|
||||||
|
der alte blaue stunde
|
||||||
|
matthias ginter
|
||||||
|
ralf schmitz
|
||||||
|
maximilian eggestein
|
||||||
|
hull city
|
||||||
|
demirovic
|
||||||
|
elton john
|
||||||
|
jeff chabot
|
||||||
|
lindt schokolade
|
||||||
|
manzambi
|
||||||
|
angelo stiller
|
||||||
|
lamine yamal verletzung
|
||||||
|
peer steinbrück
|
||||||
|
h&m
|
||||||
|
lotto 6aus49
|
||||||
|
pistons – magic
|
||||||
|
chemnitzer fc erzgebirge aue
|
||||||
|
asiago
|
||||||
|
23 nisan
|
||||||
|
sternschnuppen heute lyriden
|
||||||
|
aryna sabalenka
|
||||||
|
michael douglas
|
||||||
|
herman van veen
|
||||||
|
georgina fleur
|
||||||
|
tui
|
||||||
|
trainer bayern münchen
|
||||||
|
katie holmes
|
||||||
|
prinz frederic
|
||||||
|
bayern vs
|
||||||
|
flekken
|
||||||
|
бернли – манчестер сити
|
||||||
|
ard
|
||||||
|
queen camilla
|
||||||
|
clankriminalität
|
||||||
|
politik
|
||||||
|
gladbach-news
|
||||||
|
sara gündogan
|
||||||
|
krankenversicherung
|
||||||
|
jan-lennard struff
|
||||||
|
bryan lasme
|
||||||
|
republikanische partei
|
||||||
|
thailand
|
||||||
|
robin gosens
|
||||||
|
maremma
|
||||||
|
tennis madrid
|
||||||
|
osterburg
|
||||||
|
برايتون ضد تشيلسي
|
||||||
|
sebastian hoeneß
|
||||||
|
ncis
|
||||||
|
menowin fröhlich
|
||||||
|
maren gilzer
|
||||||
|
cineplex
|
||||||
|
gina schumacher
|
||||||
|
alexander räuscher
|
||||||
|
riza kayaalp
|
||||||
|
heppenheim
|
||||||
|
ministerpräsident
|
||||||
|
robbie williams
|
||||||
|
brian littrell
|
||||||
|
saarbrücken hauptbahnhof
|
||||||
|
frauen-bundesliga
|
||||||
|
lemgo
|
||||||
|
kommissar rex
|
||||||
|
hemsbach
|
||||||
|
benjamin weber
|
||||||
|
sydney sweeney
|
||||||
|
martin schindler
|
||||||
|
robert kennedy
|
||||||
|
antoni kowalski
|
||||||
|
luna
|
||||||
|
paris-sg – lyon
|
||||||
|
arte live
|
||||||
|
dominik kohr
|
||||||
|
dumbledores geheimnisse
|
||||||
|
kampf der realitystars
|
||||||
|
kerner
|
||||||
|
tennessee
|
||||||
|
billy idol
|
||||||
|
kfc uerdingen
|
||||||
|
bastian pastewka
|
||||||
|
gnabry
|
||||||
|
lok leipzig heute live ticker
|
||||||
|
true lies wahre lügen
|
||||||
|
челси – манчестер юнайтед
|
||||||
|
nurburgring
|
||||||
|
fortnite server status
|
||||||
|
süperlig
|
||||||
|
ronaldinho
|
||||||
|
esther schweins let's dance
|
||||||
|
michael jackson film 2026
|
||||||
|
oliver pocher
|
||||||
|
die queen film
|
||||||
|
milano
|
||||||
|
straße von hormus
|
||||||
|
motsi mabuse
|
||||||
|
rayo vallecano
|
||||||
|
harry meghan
|
||||||
|
irland
|
||||||
|
betis sevilla
|
||||||
|
vermisste person
|
||||||
|
konferenz league
|
||||||
|
garda
|
||||||
|
judith hoersch
|
||||||
|
jörg pilawa
|
||||||
|
strasbourg
|
||||||
|
real madrid vs bayern
|
||||||
|
kicker
|
||||||
|
mbappe
|
||||||
|
flashscore
|
||||||
|
sport1
|
||||||
|
vini jr
|
||||||
|
bet365
|
||||||
|
kompany
|
||||||
|
jude bellingham
|
||||||
|
upamecano
|
||||||
|
gute zeiten, schlechte zeiten
|
||||||
|
inflation
|
||||||
|
fog warning
|
||||||
|
wetter bochum
|
||||||
|
wetter aachen
|
||||||
|
wetter bonn
|
||||||
|
onet
|
||||||
|
protest
|
||||||
|
jamie dornan
|
||||||
|
heizöl
|
||||||
champions league
|
champions league
|
||||||
uefa champions league
|
uefa champions league
|
||||||
keytruda
|
keytruda
|
||||||
@@ -14,27 +198,3 @@ scarlett johansson
|
|||||||
jeff bezos
|
jeff bezos
|
||||||
dan brown
|
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
|
|
||||||
restaurant in der nähe
|
|
||||||
deutsche bahn fahrplan
|
|
||||||
urlaub buchen
|
|
||||||
rezept für kartoffelsalat
|
|
||||||
dax aktueller stand
|
|
||||||
apotheke notdienst frankfurt
|
|
||||||
günstige flüge
|
|
||||||
|
|||||||
@@ -1,3 +1,184 @@
|
|||||||
|
anthropic
|
||||||
|
prórroga alquileres congreso
|
||||||
|
sorteo bonoloto
|
||||||
|
el tiempo hoy
|
||||||
|
aemet valencia
|
||||||
|
weather
|
||||||
|
aemet
|
||||||
|
tiempo
|
||||||
|
huelga gasolineras
|
||||||
|
el tiempo
|
||||||
|
nepotismo
|
||||||
|
instituto cervantes
|
||||||
|
airbus
|
||||||
|
tiempo en bilbao
|
||||||
|
el
|
||||||
|
el tiempo en granada
|
||||||
|
spencer jones
|
||||||
|
encuesta
|
||||||
|
lili pink
|
||||||
|
meteocat
|
||||||
|
trail blazers - spurs
|
||||||
|
clasificacion segunda
|
||||||
|
20minutos
|
||||||
|
internacional de bogotá - boyacá chicó
|
||||||
|
el tiempo en valencia
|
||||||
|
lakers vs rockets
|
||||||
|
fluminense - chapecoense
|
||||||
|
rockets - lakers
|
||||||
|
heraldo de aragón
|
||||||
|
víctor muñoz villanueva
|
||||||
|
de tapas por españa
|
||||||
|
milan
|
||||||
|
aitana sánchez gijón
|
||||||
|
clasificacion liga
|
||||||
|
palencia
|
||||||
|
milan vs juventus
|
||||||
|
marseille – nice
|
||||||
|
cartagena fc
|
||||||
|
vivienda
|
||||||
|
hellas verona - lecce
|
||||||
|
marbella
|
||||||
|
alfonso vazquez mayoral fuente ymbro
|
||||||
|
bucaramanga - jaguares
|
||||||
|
toulouse - mónaco
|
||||||
|
eldense
|
||||||
|
nicolai budkov kjær
|
||||||
|
aryna sabalenka
|
||||||
|
jaqueline cristian
|
||||||
|
rafa jodar
|
||||||
|
samantha vallejo-nágera
|
||||||
|
ريال بتيس ضد الريال
|
||||||
|
nvidia
|
||||||
|
rafael jódar
|
||||||
|
jodar tenista
|
||||||
|
sunderland afc - nottingham forest
|
||||||
|
rb leipzig - fc union berlin
|
||||||
|
julián alvarez
|
||||||
|
stade brestois - lens
|
||||||
|
clasificación de primera división
|
||||||
|
javier hidalgo
|
||||||
|
cayetano martínez de irujo
|
||||||
|
llanes
|
||||||
|
vfb stuttgart – freiburg
|
||||||
|
roca rey
|
||||||
|
psv - zwolle
|
||||||
|
daredevil
|
||||||
|
a que estas esperando
|
||||||
|
real oviedo - villarreal
|
||||||
|
real salt lake - inter miami
|
||||||
|
pistons - magic
|
||||||
|
barcelona sc - mushuc runa
|
||||||
|
kick
|
||||||
|
raphinha
|
||||||
|
lluvia estrellas liridas
|
||||||
|
frenkie de jong
|
||||||
|
santos - coritiba
|
||||||
|
del cerro grande
|
||||||
|
phillip cocu
|
||||||
|
cospedal
|
||||||
|
david wilcock
|
||||||
|
barcelona - celta de vigo
|
||||||
|
barcelone – celta vigo
|
||||||
|
macarena gómez
|
||||||
|
luis merlo
|
||||||
|
bournemouth vs leeds
|
||||||
|
racing de estrasburgo - niza
|
||||||
|
burnley vs man city
|
||||||
|
alaska cantante
|
||||||
|
raúl gonzález blanco
|
||||||
|
marta sanchez
|
||||||
|
roberto bautista
|
||||||
|
cifras y letras
|
||||||
|
xbox game pass ultimate
|
||||||
|
horse powertrain
|
||||||
|
las hurdes
|
||||||
|
herbicida cancer colon
|
||||||
|
lluvia de barro
|
||||||
|
ripoll
|
||||||
|
manilva
|
||||||
|
steve jobs
|
||||||
|
berrettini
|
||||||
|
prizmic
|
||||||
|
laura moure
|
||||||
|
lens - toulouse
|
||||||
|
girona vs real betis
|
||||||
|
yuri berchiche
|
||||||
|
posiciones de la liga
|
||||||
|
resultados liga
|
||||||
|
lfp
|
||||||
|
umar sadiq
|
||||||
|
реал мадрид – алавес
|
||||||
|
jan virgili
|
||||||
|
moreirense - estoril
|
||||||
|
downton abbey
|
||||||
|
koldo garcía izaguirre
|
||||||
|
jorge martín
|
||||||
|
mike james
|
||||||
|
carla leite
|
||||||
|
eclipse solar del 12 de agosto de 2026
|
||||||
|
crystal palace - west ham
|
||||||
|
luz valdenebro
|
||||||
|
porto - tondela
|
||||||
|
santos - fluminense
|
||||||
|
juventus
|
||||||
|
almería - málaga
|
||||||
|
punjab kings vs lucknow super giants standings
|
||||||
|
mönchengladbach – mainz
|
||||||
|
victor eloy
|
||||||
|
paris-sg – lyon
|
||||||
|
psg vs lyon
|
||||||
|
zamora - osasuna b
|
||||||
|
estrecho
|
||||||
|
nurburgring
|
||||||
|
la 1 directo
|
||||||
|
oyarzabal
|
||||||
|
enrique cerezo
|
||||||
|
fraude
|
||||||
|
tasa
|
||||||
|
la 1
|
||||||
|
tve directo
|
||||||
|
cuántas copas del rey tiene la real sociedad
|
||||||
|
eugenia martínez de irujo
|
||||||
|
ccoo
|
||||||
|
racing de santander
|
||||||
|
racing
|
||||||
|
baliza v16
|
||||||
|
st. pauli – köln
|
||||||
|
iphone 18
|
||||||
|
st. pauli - colonia
|
||||||
|
nico paz
|
||||||
|
lionel messi
|
||||||
|
armengol
|
||||||
|
pau víctor
|
||||||
|
braga fc
|
||||||
|
fiorentina vs crystal palace
|
||||||
|
morante hoy
|
||||||
|
iago aspas
|
||||||
|
aston villa
|
||||||
|
real betis vs braga
|
||||||
|
ministerio de sanidad
|
||||||
|
az - shakhtar
|
||||||
|
arsenal
|
||||||
|
tiktok
|
||||||
|
harry kane
|
||||||
|
sudan
|
||||||
|
lunin
|
||||||
|
airef
|
||||||
|
tiempo de juego
|
||||||
|
fc bayern
|
||||||
|
militao
|
||||||
|
bellingham
|
||||||
|
supervivientes
|
||||||
|
jalen green
|
||||||
|
rockstar games
|
||||||
|
bam adebayo
|
||||||
|
china
|
||||||
|
suns - trail blazers
|
||||||
|
euromillones
|
||||||
|
ldu quito - mirassol
|
||||||
|
davion mitchell
|
||||||
|
universitario - coquimbo unido
|
||||||
El País
|
El País
|
||||||
Marca
|
Marca
|
||||||
RTVE Noticias
|
RTVE Noticias
|
||||||
|
|||||||
@@ -1,3 +1,180 @@
|
|||||||
|
meteo le mans
|
||||||
|
meteo caen
|
||||||
|
bernard cazeneuve
|
||||||
|
vignoble
|
||||||
|
forest automobile
|
||||||
|
brown-forman
|
||||||
|
meteo quimper
|
||||||
|
meteo brest
|
||||||
|
charles iii
|
||||||
|
montceau news
|
||||||
|
taylor swift
|
||||||
|
meteo amiens
|
||||||
|
salle de bal
|
||||||
|
reine camilla
|
||||||
|
david hockney
|
||||||
|
jacques dutronc
|
||||||
|
franck thilliez
|
||||||
|
squamish
|
||||||
|
nasa
|
||||||
|
nba spurs portland
|
||||||
|
mourad zeghidi
|
||||||
|
maries au premier regard episode 10
|
||||||
|
tchad
|
||||||
|
meteofrance
|
||||||
|
meteo grenoble
|
||||||
|
film
|
||||||
|
meteo vannes
|
||||||
|
cnews direct
|
||||||
|
toulouse – clermont
|
||||||
|
martin short
|
||||||
|
le diable s'habille en prada 2 sortie
|
||||||
|
gautier larsonneur
|
||||||
|
milan vs juventus
|
||||||
|
stanley tucci
|
||||||
|
avs – sporting
|
||||||
|
lambert wilson
|
||||||
|
tochukwu nnadi
|
||||||
|
greenwood
|
||||||
|
jaqueline cristian
|
||||||
|
thomas ramos
|
||||||
|
om nice
|
||||||
|
bordeaux-bègles – montpellier
|
||||||
|
drone
|
||||||
|
rochdale association football club
|
||||||
|
doctor who
|
||||||
|
c à vous c à vous
|
||||||
|
sabalenka
|
||||||
|
national 2 groupe a
|
||||||
|
lena situation
|
||||||
|
rafael jódar
|
||||||
|
mask singer
|
||||||
|
alex de minaur
|
||||||
|
oyonnax – agen
|
||||||
|
lucie castets
|
||||||
|
napoli - cremonese
|
||||||
|
ligue1+
|
||||||
|
agnes lassalle
|
||||||
|
jean luc reichmann
|
||||||
|
m6
|
||||||
|
caitlyn jenner
|
||||||
|
star academy
|
||||||
|
bfm marseille provence
|
||||||
|
hunter schafer
|
||||||
|
unchosen netflix
|
||||||
|
john travolta
|
||||||
|
valence-romans – brive
|
||||||
|
reem kherici
|
||||||
|
will smith
|
||||||
|
real salt lake – inter miami
|
||||||
|
neymar
|
||||||
|
les traîtres
|
||||||
|
jacob elordi
|
||||||
|
pistons – magic
|
||||||
|
invincible
|
||||||
|
santos – coritiba
|
||||||
|
ios 18
|
||||||
|
la liga
|
||||||
|
royaume uni interdiction tabac
|
||||||
|
stephane tapie
|
||||||
|
tondelier
|
||||||
|
benjamin duhamel
|
||||||
|
loto 22 avril 2026
|
||||||
|
interdiction tabac royaume uni
|
||||||
|
lol qui rit sort
|
||||||
|
eva longoria
|
||||||
|
alain bauer
|
||||||
|
achraf hakimi
|
||||||
|
ibrahim mbaye
|
||||||
|
mma
|
||||||
|
roberto calvet
|
||||||
|
budget
|
||||||
|
coupe du monde de football 2006
|
||||||
|
plus belle la vie en avance
|
||||||
|
mateus fernandes
|
||||||
|
tour des alpes 2026
|
||||||
|
lorenzo finn
|
||||||
|
maine-et-loire
|
||||||
|
mathieu flamini
|
||||||
|
kamel daoud
|
||||||
|
vandalisme
|
||||||
|
sydney sweeney
|
||||||
|
julien odoul
|
||||||
|
france2
|
||||||
|
xavier dupont de ligonnès
|
||||||
|
elisabeth 2
|
||||||
|
antibes
|
||||||
|
girona – betis
|
||||||
|
christine bravo
|
||||||
|
الريال ضد ألافيس
|
||||||
|
madonna age
|
||||||
|
margot haddad
|
||||||
|
ana riera
|
||||||
|
hinaupoko devèze
|
||||||
|
bruce toussaint
|
||||||
|
cheque energie
|
||||||
|
reid wiseman
|
||||||
|
loto 20 avril 2026
|
||||||
|
from serie
|
||||||
|
toulouse
|
||||||
|
racing 92 – stade français
|
||||||
|
juventus - bologna
|
||||||
|
film une annee difficile
|
||||||
|
échouement
|
||||||
|
programme tv ce soir
|
||||||
|
porto – tondela
|
||||||
|
matthieu pigasse
|
||||||
|
santos – fluminense
|
||||||
|
gta 6
|
||||||
|
laetitia milot
|
||||||
|
loto 18 avril 2026
|
||||||
|
bercy
|
||||||
|
pierre lellouche
|
||||||
|
adele
|
||||||
|
adil rami
|
||||||
|
castres – toulouse
|
||||||
|
angel
|
||||||
|
stéphane bern
|
||||||
|
anne claire coudray
|
||||||
|
pmu résultat
|
||||||
|
laury thilleman et paul mirabel
|
||||||
|
quinté du jour
|
||||||
|
euromillions 17 avril 2026
|
||||||
|
uson
|
||||||
|
guillaume meurice
|
||||||
|
pmu
|
||||||
|
grenoble – oyonnax
|
||||||
|
bagarre
|
||||||
|
programme télé
|
||||||
|
tchernobyl
|
||||||
|
géraldine maillet
|
||||||
|
biot
|
||||||
|
racing
|
||||||
|
liga europa
|
||||||
|
tv ce soir
|
||||||
|
programme tv de ce soir
|
||||||
|
brad pitt
|
||||||
|
aston villa
|
||||||
|
michael olise
|
||||||
|
robert ménard
|
||||||
|
match ce soir
|
||||||
|
sporting
|
||||||
|
ester exposito
|
||||||
|
bellingham
|
||||||
|
iptv
|
||||||
|
militao
|
||||||
|
jeff goldblum
|
||||||
|
lunin
|
||||||
|
kiev
|
||||||
|
julien royal
|
||||||
|
viktor orbán
|
||||||
|
aqababe
|
||||||
|
nhl
|
||||||
|
suns – trail blazers
|
||||||
|
bam adebayo
|
||||||
|
davion mitchell
|
||||||
|
l
|
||||||
|
santos – recoleta football club
|
||||||
atletico madrid
|
atletico madrid
|
||||||
tf1
|
tf1
|
||||||
uefa champions league
|
uefa champions league
|
||||||
@@ -14,7 +191,6 @@ loto du 13 avril 2026
|
|||||||
juan arbeláez
|
juan arbeláez
|
||||||
hbo
|
hbo
|
||||||
katy perry justin trudeau
|
katy perry justin trudeau
|
||||||
jacob elordi
|
|
||||||
tondela – gil vicente
|
tondela – gil vicente
|
||||||
le rugbynistère
|
le rugbynistère
|
||||||
epstein
|
epstein
|
||||||
@@ -22,18 +198,3 @@ kino
|
|||||||
horoscope du 13 avril 2026
|
horoscope du 13 avril 2026
|
||||||
golf masters augusta 2026
|
golf masters augusta 2026
|
||||||
boursorama bourse
|
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
|
|
||||||
pharmacie de garde
|
|
||||||
horaires sncf
|
|
||||||
recette crêpes
|
|
||||||
cac 40 en direct
|
|
||||||
acheter billet louvre
|
|
||||||
boulangerie autour de moi
|
|
||||||
carte vitale ameli
|
|
||||||
|
|||||||
@@ -1,5 +1,173 @@
|
|||||||
liverpool vs psg
|
異環兌換碼
|
||||||
|
洪金宝
|
||||||
|
梁嘉莹
|
||||||
|
spurs vs trail blazers
|
||||||
|
羅艷卿
|
||||||
|
weather forecast
|
||||||
|
observatory hk
|
||||||
|
尼克 對 老鷹
|
||||||
|
sfc
|
||||||
|
馬刺 對 拓荒者
|
||||||
|
粉嶺繞道
|
||||||
|
nuggets vs timberwolves
|
||||||
|
蔡卓妍
|
||||||
|
港 漂
|
||||||
|
suns vs thunder
|
||||||
|
鍾澍佳
|
||||||
|
萧正楠
|
||||||
|
金塊 對 灰狼
|
||||||
|
魔術 對 活塞
|
||||||
|
太陽 對 雷霆
|
||||||
|
港 人 北上
|
||||||
|
hsbc
|
||||||
|
何守信
|
||||||
|
謝賢
|
||||||
|
房協
|
||||||
|
rockets vs lakers
|
||||||
|
火箭 對 湖人
|
||||||
|
曾志偉
|
||||||
|
簡淑兒
|
||||||
|
北海道地震
|
||||||
|
莫 雷 拉
|
||||||
|
蔡一傑
|
||||||
|
車路士
|
||||||
|
羅志祥
|
||||||
|
自助餐
|
||||||
|
馮盈盈
|
||||||
|
無時空之戀
|
||||||
|
方力申
|
||||||
|
可嵐
|
||||||
|
切爾西 對 里茲聯
|
||||||
|
谷 婭 溦
|
||||||
|
曼城
|
||||||
|
印度
|
||||||
|
英超
|
||||||
利物浦
|
利物浦
|
||||||
|
pl
|
||||||
|
arsenal vs newcastle
|
||||||
|
premier league standings
|
||||||
|
曼城 對 南安普敦
|
||||||
|
寒戰
|
||||||
|
米高積遜
|
||||||
|
jaafar jackson
|
||||||
|
nvda
|
||||||
|
吳業坤
|
||||||
|
麻疹
|
||||||
|
林盛斌
|
||||||
|
cuaca besok
|
||||||
|
明天的天氣
|
||||||
|
weather tomorrow
|
||||||
|
rthk
|
||||||
|
weather hong kong
|
||||||
|
天文台
|
||||||
|
hk observatory
|
||||||
|
observatory
|
||||||
|
csk vs mi
|
||||||
|
長沙灣
|
||||||
|
魔音女團
|
||||||
|
球迷世界
|
||||||
|
天星銀行
|
||||||
|
game
|
||||||
|
林嘉華
|
||||||
|
套餐
|
||||||
|
賈曉晨
|
||||||
|
hk weather
|
||||||
|
綠色債券
|
||||||
|
barcelona vs celta vigo
|
||||||
|
weather
|
||||||
|
7-eleven
|
||||||
|
天气
|
||||||
|
班來 對 曼城
|
||||||
|
埃爾切 對 馬德里競技
|
||||||
|
rosenior
|
||||||
|
艾納斯
|
||||||
|
liam rosenior
|
||||||
|
巴黎聖日耳曼 對 南特
|
||||||
|
chatgpt image 2
|
||||||
|
啟德醫院
|
||||||
|
李泳漢老婆
|
||||||
|
破產
|
||||||
|
繼承人
|
||||||
|
英皇群星演唱會
|
||||||
|
布浩榮
|
||||||
|
新聞
|
||||||
|
貨幣貶值
|
||||||
|
居 屋 2025
|
||||||
|
3988
|
||||||
|
李泳豪老婆
|
||||||
|
皇家馬德里 對 艾拉維斯
|
||||||
|
李泳漢
|
||||||
|
鄭欣宜
|
||||||
|
srh vs dc
|
||||||
|
鍾嘉欣
|
||||||
|
張柏芝
|
||||||
|
江美儀
|
||||||
|
全港戲院日 2026
|
||||||
|
江旻憓
|
||||||
|
陶傑
|
||||||
|
水晶宮 對 西漢姆聯
|
||||||
|
吉達艾阿里
|
||||||
|
山口智子
|
||||||
|
百佳超級市場
|
||||||
|
利息
|
||||||
|
戴祖儀
|
||||||
|
陳若思
|
||||||
|
麥當勞
|
||||||
|
首岸
|
||||||
|
中国商飞c919
|
||||||
|
bundesliga
|
||||||
|
hailey bieber
|
||||||
|
德甲
|
||||||
|
cherki
|
||||||
|
now
|
||||||
|
now tv
|
||||||
|
al nassr
|
||||||
|
洪金寶
|
||||||
|
曼聯
|
||||||
|
切爾西 對 曼聯
|
||||||
|
何沛珈
|
||||||
|
熱刺
|
||||||
|
tottenham vs brighton
|
||||||
|
熱刺 對 布萊頓
|
||||||
|
epl
|
||||||
|
司機
|
||||||
|
补贴
|
||||||
|
華富邨
|
||||||
|
零售
|
||||||
|
藍莓
|
||||||
|
商湯科技
|
||||||
|
周國豐
|
||||||
|
啟點
|
||||||
|
歐聯
|
||||||
|
神戶勝利船
|
||||||
|
潘宏彬
|
||||||
|
姚正菁
|
||||||
|
木乃伊
|
||||||
|
ios 26
|
||||||
|
李克寧木乃伊
|
||||||
|
田啟文
|
||||||
|
曼寧加
|
||||||
|
arsenal
|
||||||
|
ucl
|
||||||
|
歐洲聯賽冠軍盃
|
||||||
|
arsenal vs sporting
|
||||||
|
bayern vs real madrid
|
||||||
|
real madrid
|
||||||
|
皇馬
|
||||||
|
拜仁慕尼黑 對 皇家馬德里
|
||||||
|
claude
|
||||||
|
補貼
|
||||||
|
nba 直播
|
||||||
|
航空公司
|
||||||
|
向華強
|
||||||
|
李嘉欣
|
||||||
|
typhoon
|
||||||
|
nba
|
||||||
|
nba線上看
|
||||||
|
nba直播
|
||||||
|
全民國家安全教育日
|
||||||
|
運輸署
|
||||||
|
liverpool vs psg
|
||||||
barcelona
|
barcelona
|
||||||
歐冠
|
歐冠
|
||||||
馬德里競技 對 巴塞隆納
|
馬德里競技 對 巴塞隆納
|
||||||
@@ -15,7 +183,6 @@ prediction market
|
|||||||
polymarket
|
polymarket
|
||||||
巴基斯坦
|
巴基斯坦
|
||||||
sndk
|
sndk
|
||||||
江美儀
|
|
||||||
楊何蓓茵
|
楊何蓓茵
|
||||||
樂珈嘉
|
樂珈嘉
|
||||||
姜濤
|
姜濤
|
||||||
@@ -31,10 +198,3 @@ livenation
|
|||||||
香港天文台天氣預報
|
香港天文台天氣預報
|
||||||
MTR 港鐵路線圖
|
MTR 港鐵路線圖
|
||||||
OpenRice 附近美食
|
OpenRice 附近美食
|
||||||
LIHKG 討論區
|
|
||||||
恆生指數今日行情
|
|
||||||
SCMP breaking news
|
|
||||||
HKEX 港交所股價
|
|
||||||
國泰航空航班狀態
|
|
||||||
香港迪士尼樂園門票
|
|
||||||
百佳超級市場網購
|
|
||||||
|
|||||||
@@ -1,8 +1,183 @@
|
|||||||
リバプール
|
ベガルタ仙台
|
||||||
abema
|
サンフレッチェ広島
|
||||||
champions league
|
相模原 対 栃木c
|
||||||
wowow
|
ロッチ中岡
|
||||||
|
奈良 対 高知
|
||||||
|
福島圭音
|
||||||
|
神宮球場
|
||||||
|
オスナ ヤクルト
|
||||||
|
藤枝myfc
|
||||||
|
浦和 対 川崎f
|
||||||
|
村上宗隆
|
||||||
|
ゴー イントゥ スカイ
|
||||||
|
地球温暖化
|
||||||
|
文部科学省
|
||||||
|
カベポスター
|
||||||
|
奈良県
|
||||||
|
バナナマン日村
|
||||||
|
山本由伸
|
||||||
|
警視正
|
||||||
|
中国電力
|
||||||
|
jr九州
|
||||||
|
村田製作所
|
||||||
|
四谷大塚
|
||||||
|
外崎 修 汰
|
||||||
|
備蓄
|
||||||
|
日産 キックス 新型
|
||||||
|
ドナルド・トランプ
|
||||||
|
ニューヨーク
|
||||||
|
小谷昌太郎 イケパラ
|
||||||
|
東京エレクトロン
|
||||||
|
ミラン 対 ユヴェントス
|
||||||
|
宇連ダム 貯水率
|
||||||
|
櫻坂46
|
||||||
|
与沢翼
|
||||||
|
岩手県 大槌町 山林火災
|
||||||
|
谷原章介
|
||||||
|
端午
|
||||||
|
週間天気予報
|
||||||
|
トリノ 対 インテル
|
||||||
|
佐野海舟
|
||||||
|
アーセナル
|
||||||
|
高岡蒼佑
|
||||||
|
マンチェスター・シティfc
|
||||||
|
ゲンク 対 スタンダール
|
||||||
|
kick
|
||||||
|
chat gpt
|
||||||
|
hulu
|
||||||
|
nac 対 アヤックス
|
||||||
|
エプスタイン
|
||||||
|
arsenal đấu với newcastle
|
||||||
|
ベティス 対 rマドリード
|
||||||
|
dior
|
||||||
|
伊藤美来
|
||||||
|
フィギュア
|
||||||
|
玉置浩二
|
||||||
|
生田絵梨花
|
||||||
|
日本高野連会長辞任
|
||||||
|
anaheim
|
||||||
|
sbiグローバルアセットマネジメント
|
||||||
|
ストレンジャーシングス
|
||||||
|
石油
|
||||||
|
ios 26.4 2
|
||||||
|
ポケモンカード
|
||||||
|
シュトゥットガルト 対 フライブルク
|
||||||
|
ドラクエ スマグロ 攻略
|
||||||
|
ipl
|
||||||
|
アコム
|
||||||
|
鈴木愛理
|
||||||
|
sox指数
|
||||||
|
村上世彰
|
||||||
|
桐山 照史
|
||||||
|
マラッカ海峡
|
||||||
|
ソニック
|
||||||
|
sbi新生銀行 株価
|
||||||
|
マイクラ
|
||||||
|
川口 春奈
|
||||||
|
サンダー 対 サンズ
|
||||||
|
インフルエンサー
|
||||||
|
サンケイビル
|
||||||
|
岡村隆史
|
||||||
|
上田竜也
|
||||||
|
メタプラネット
|
||||||
|
バルセロナ 対 セルタ
|
||||||
|
三橋くん
|
||||||
エルニーニョ
|
エルニーニョ
|
||||||
|
バーンリー 対 マンc
|
||||||
|
ボーンマス 対 リーズ u
|
||||||
|
elche vs atlético madrid
|
||||||
|
レバークーゼン 対 バイエルン
|
||||||
|
ソシエダ 対 ヘタフェ
|
||||||
|
サイメモリ
|
||||||
|
b リーグ 順位
|
||||||
|
日ハム
|
||||||
|
ナダル
|
||||||
|
失点
|
||||||
|
岩瀬洋志
|
||||||
|
ファイターズ 試合
|
||||||
|
江村美咲
|
||||||
|
宝島社
|
||||||
|
井ノ原 快彦
|
||||||
|
ファイターズ
|
||||||
|
西郷隆盛
|
||||||
|
ボーダー
|
||||||
|
チェルシー
|
||||||
|
関税
|
||||||
|
ブライトン
|
||||||
|
佳子内親王
|
||||||
|
rマドリード 対 アラベス
|
||||||
|
鳥貴族
|
||||||
|
ブライトン 対 チェルシー
|
||||||
|
アシエンダ乗馬学校
|
||||||
|
ngày trái đất
|
||||||
|
加藤小夏
|
||||||
|
町田ゼルビア
|
||||||
|
モンスターハンターシリーズ
|
||||||
|
クリスタル・パレス 対 ウェストハム
|
||||||
|
吉田正尚
|
||||||
|
旭琉會
|
||||||
|
神戸
|
||||||
|
てんちむ
|
||||||
|
浜辺美波
|
||||||
|
デーブ ロバーツ
|
||||||
|
皇治
|
||||||
|
小雪
|
||||||
|
にじさんじデビュー
|
||||||
|
ちゃんよた
|
||||||
|
坂本 花織
|
||||||
|
松山 千春
|
||||||
|
リーグアン
|
||||||
|
伊勢谷友介
|
||||||
|
bayern vs vfb stuttgart
|
||||||
|
chelsea vs man united
|
||||||
|
唐田えりか
|
||||||
|
102回目のプロポーズ
|
||||||
|
デゼルビ
|
||||||
|
アトレティコ 対 ソシエダ
|
||||||
|
チェルシー 対 マンu
|
||||||
|
スパーズ
|
||||||
|
清春
|
||||||
|
ディエゴ・ゴメス
|
||||||
|
ps5
|
||||||
|
ハイウェイ の 堕 天使 興行 収入
|
||||||
|
カブス 対 メッツ
|
||||||
|
dazn
|
||||||
|
サッスオーロ 対 コモ
|
||||||
|
杉咲花
|
||||||
|
町田 対 アル・イテハド
|
||||||
|
家計
|
||||||
|
週末旅の極意
|
||||||
|
北斗の拳
|
||||||
|
qvc
|
||||||
|
小芝風花
|
||||||
|
中井亜美
|
||||||
|
afc u20女子アジアカップ
|
||||||
|
ネオジオ
|
||||||
|
uefaヨーロッパリーグ
|
||||||
|
加藤史帆
|
||||||
|
志田未来
|
||||||
|
伊藤英明
|
||||||
|
島田麻央
|
||||||
|
al-nassr vs al-ettifaq
|
||||||
|
arsenal
|
||||||
|
レアル・マドリード
|
||||||
|
バイエルン
|
||||||
|
abema
|
||||||
|
real madrid
|
||||||
|
lucknow super giants vs royal challengers bengaluru standings
|
||||||
|
bayern vs real madrid
|
||||||
|
給付
|
||||||
|
wowow
|
||||||
|
小泉進次郎
|
||||||
|
政権
|
||||||
|
ミキティ
|
||||||
|
今日のドジャースの結果
|
||||||
|
新名神高速道路
|
||||||
|
わたせせいぞう
|
||||||
|
ピーチ航空
|
||||||
|
アレックス・ベシア
|
||||||
|
リバプール
|
||||||
|
champions league
|
||||||
アトレティコ 対 バルセロナ
|
アトレティコ 対 バルセロナ
|
||||||
オープンワールド
|
オープンワールド
|
||||||
atlético madrid vs barcelona
|
atlético madrid vs barcelona
|
||||||
@@ -23,14 +198,3 @@ man united vs leeds
|
|||||||
高見沢 俊彦
|
高見沢 俊彦
|
||||||
不登校
|
不登校
|
||||||
後期高齢者医療制度
|
後期高齢者医療制度
|
||||||
バーミヤン
|
|
||||||
宮澤エマ
|
|
||||||
チケプラ
|
|
||||||
横綱
|
|
||||||
宮里美香
|
|
||||||
東京 天気 明日
|
|
||||||
新宿 おすすめ 居酒屋
|
|
||||||
最新のニュース 速報
|
|
||||||
ゴールド 相場 チャート
|
|
||||||
近くの静かなカフェ
|
|
||||||
円安 影響 生活
|
|
||||||
|
|||||||
159
data/keywords/kw_KR.txt
Normal file
159
data/keywords/kw_KR.txt
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
변호사 시험
|
||||||
|
금보유고
|
||||||
|
이상화
|
||||||
|
커피
|
||||||
|
김효범
|
||||||
|
김범석
|
||||||
|
국립중앙도서관
|
||||||
|
어도어
|
||||||
|
황재균
|
||||||
|
주호민
|
||||||
|
채원빈
|
||||||
|
분식
|
||||||
|
위례신도시
|
||||||
|
박동혁
|
||||||
|
박용호
|
||||||
|
한화첨단소재
|
||||||
|
한상진
|
||||||
|
차승원
|
||||||
|
한국경제
|
||||||
|
효성중공업
|
||||||
|
최홍라
|
||||||
|
uae vs oman
|
||||||
|
mlb
|
||||||
|
부정승차
|
||||||
|
박하나
|
||||||
|
일본인
|
||||||
|
공천
|
||||||
|
한고은
|
||||||
|
우체국
|
||||||
|
sk증권
|
||||||
|
세리에 a
|
||||||
|
암호화폐
|
||||||
|
수지
|
||||||
|
새마을금고
|
||||||
|
사주
|
||||||
|
차두리
|
||||||
|
평택시 을
|
||||||
|
야닉 시너
|
||||||
|
정성호
|
||||||
|
첼시
|
||||||
|
psg
|
||||||
|
리그앙
|
||||||
|
arsenal đấu với newcastle
|
||||||
|
맨시티
|
||||||
|
man city đấu với southampton
|
||||||
|
아스널
|
||||||
|
arsenal vs newcastle
|
||||||
|
아스널 대 뉴캐슬
|
||||||
|
man city vs southampton
|
||||||
|
안보현
|
||||||
|
트와이스
|
||||||
|
s
|
||||||
|
엔비디아 주가
|
||||||
|
이경실
|
||||||
|
신발
|
||||||
|
하현상
|
||||||
|
김수희
|
||||||
|
gt vs rcb
|
||||||
|
amd 주가
|
||||||
|
왕다루
|
||||||
|
시그널
|
||||||
|
모하메드 살라
|
||||||
|
공화당
|
||||||
|
윤하정
|
||||||
|
청남대
|
||||||
|
더보이즈
|
||||||
|
노민우
|
||||||
|
서비스나우
|
||||||
|
김민지
|
||||||
|
박해미
|
||||||
|
국가유산청
|
||||||
|
삼성전자 주가
|
||||||
|
두산에너빌리티 주가
|
||||||
|
김성수
|
||||||
|
한국사
|
||||||
|
삼성전기 주가
|
||||||
|
국립중앙박물관
|
||||||
|
대우건설 주가
|
||||||
|
지방 선거
|
||||||
|
서정대학교
|
||||||
|
캔바
|
||||||
|
한국항공우주산업
|
||||||
|
디트로이트 대 올랜도
|
||||||
|
리그 1
|
||||||
|
elche vs atlético madrid
|
||||||
|
알나스르
|
||||||
|
al-nassr vs al ahli
|
||||||
|
10
|
||||||
|
로세니어
|
||||||
|
psg 대 낭트
|
||||||
|
테슬라 실적발표
|
||||||
|
루카스 모우라
|
||||||
|
9950x3d2
|
||||||
|
삼천당 제약 간담회
|
||||||
|
김재윤
|
||||||
|
k리그1 순위
|
||||||
|
유영찬
|
||||||
|
이호연
|
||||||
|
sxmb
|
||||||
|
진
|
||||||
|
문재인
|
||||||
|
생산직
|
||||||
|
강훈식
|
||||||
|
롤
|
||||||
|
cnn
|
||||||
|
리그오브레전드
|
||||||
|
박환희
|
||||||
|
박지현
|
||||||
|
카토
|
||||||
|
와우넷
|
||||||
|
지구의 날
|
||||||
|
컴프야
|
||||||
|
차지연
|
||||||
|
크리스털 팰리스 대 웨스트 햄
|
||||||
|
비상계엄
|
||||||
|
연기금
|
||||||
|
배틀그라운드
|
||||||
|
제이홉
|
||||||
|
두산로보틱스
|
||||||
|
부부
|
||||||
|
미노이 우원재
|
||||||
|
danish malewar
|
||||||
|
mi vs gt
|
||||||
|
양치 승
|
||||||
|
프리미어리그
|
||||||
|
pl
|
||||||
|
bundesliga
|
||||||
|
맨체스터 시티 fc
|
||||||
|
fotmob
|
||||||
|
윤아
|
||||||
|
김영인
|
||||||
|
манчестер сити – арсенал
|
||||||
|
케이뱅크
|
||||||
|
날씨
|
||||||
|
환율
|
||||||
|
손흥민
|
||||||
|
토트넘 경기 일정
|
||||||
|
넷플릭스
|
||||||
|
국민은행
|
||||||
|
네이버웹툰
|
||||||
|
로또 당첨번호
|
||||||
|
쿠팡
|
||||||
|
KBO 리그
|
||||||
|
프로야구 순위
|
||||||
|
아이폰 15
|
||||||
|
챗gpt
|
||||||
|
인스타그램
|
||||||
|
유튜브 밴스드
|
||||||
|
이강인
|
||||||
|
김민재
|
||||||
|
LCK 일정
|
||||||
|
T1
|
||||||
|
페이커
|
||||||
|
무빙
|
||||||
|
카카오톡 PC버전
|
||||||
|
당근마켓
|
||||||
|
배달의민족
|
||||||
|
올리브영
|
||||||
|
메이플스토리
|
||||||
93
data/keywords/kw_MY.txt
Normal file
93
data/keywords/kw_MY.txt
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
marissa dania hakim
|
||||||
|
oma vs nep
|
||||||
|
ppv
|
||||||
|
mothers day
|
||||||
|
nte redeem code
|
||||||
|
skyechip
|
||||||
|
马刺 - 开拓者
|
||||||
|
one championship live
|
||||||
|
labour day
|
||||||
|
indonesia thomas cup
|
||||||
|
anggota tentera
|
||||||
|
阿sa
|
||||||
|
掘金 - 森林狼
|
||||||
|
one championship
|
||||||
|
apple iphone foldable
|
||||||
|
太阳 - 雷霆
|
||||||
|
p1p plate
|
||||||
|
nuggets vs timberwolves
|
||||||
|
electronic invoicing
|
||||||
|
malaysian meteorological department
|
||||||
|
datuk seri aminuddin harun
|
||||||
|
court
|
||||||
|
bella astillah
|
||||||
|
today wordle hints
|
||||||
|
ezi ray 01
|
||||||
|
lakers
|
||||||
|
uae vs oman
|
||||||
|
rekod dunia
|
||||||
|
mayat
|
||||||
|
milan vs juventus
|
||||||
|
osasuna vs sevilla
|
||||||
|
estrela amadora vs porto
|
||||||
|
lockheed martin
|
||||||
|
galatasaray vs fenerbahçe
|
||||||
|
polis
|
||||||
|
torino vs inter
|
||||||
|
terengganu fc
|
||||||
|
angkrish raghuvanshi
|
||||||
|
dortmund vs sc freiburg
|
||||||
|
atlético madrid vs athletic club
|
||||||
|
fa cup games
|
||||||
|
แมนซิตี พบ เซาแธมป์ตัน
|
||||||
|
benfica vs moreirense
|
||||||
|
city
|
||||||
|
valencia vs girona
|
||||||
|
man city games
|
||||||
|
bayern vs barcelona
|
||||||
|
英超积分榜
|
||||||
|
angers vs psg
|
||||||
|
sunderland vs nottm forest
|
||||||
|
real betis lwn real madrid cf
|
||||||
|
napoli vs cremonese
|
||||||
|
real betis vs real madrid
|
||||||
|
perfect crown ep 5
|
||||||
|
siti mastura mohamad
|
||||||
|
jannik sinner
|
||||||
|
sai sudharsan
|
||||||
|
yaris cross hybrid
|
||||||
|
cretaceous kraken
|
||||||
|
rayo vallecano vs espanyol
|
||||||
|
dji lito x1
|
||||||
|
levante vs sevilla
|
||||||
|
danish malewar
|
||||||
|
mukesh choudhary
|
||||||
|
lyrid meteor showers
|
||||||
|
jamie overton
|
||||||
|
piala uber
|
||||||
|
madrid open
|
||||||
|
dewald brevis
|
||||||
|
counter strike
|
||||||
|
pistons vs magic
|
||||||
|
real salt lake vs inter miami
|
||||||
|
chart gpt
|
||||||
|
asiago
|
||||||
|
liza hanim
|
||||||
|
good morning
|
||||||
|
pandikar amin mulia
|
||||||
|
勒沃库森 - 拜仁
|
||||||
|
santos vs coritiba
|
||||||
|
Malaysia
|
||||||
|
Kuala Lumpur
|
||||||
|
Bursa Malaysia
|
||||||
|
Ringgit
|
||||||
|
Maybank
|
||||||
|
CIMB
|
||||||
|
Shopee MY
|
||||||
|
Lazada Malaysia
|
||||||
|
KWSP i-Akaun
|
||||||
|
LHDN MyTax
|
||||||
|
Anwar Ibrahim
|
||||||
|
Johor Bahru
|
||||||
|
Penang
|
||||||
|
Nasi Lemak
|
||||||
30
data/keywords/kw_NG.txt
Normal file
30
data/keywords/kw_NG.txt
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
william ruto
|
||||||
|
spurs vs trail blazers
|
||||||
|
celtics vs 76ers
|
||||||
|
ahsoka tano replacement star wars
|
||||||
|
san lorenzo vs santos
|
||||||
|
the devil wears prada 2
|
||||||
|
king charles
|
||||||
|
house of the dragon season 3
|
||||||
|
gta 5
|
||||||
|
top scorer in champions league
|
||||||
|
nuggets vs timberwolves
|
||||||
|
suns vs thunder
|
||||||
|
magic vs pistons
|
||||||
|
ig
|
||||||
|
bybit
|
||||||
|
jack grealish
|
||||||
|
sanwo olu
|
||||||
|
saheed balogun
|
||||||
|
man u fc
|
||||||
|
live score today
|
||||||
|
tinubu
|
||||||
|
lagos weather
|
||||||
|
nigeria news
|
||||||
|
super eagles
|
||||||
|
naira exchange rate
|
||||||
|
davido
|
||||||
|
wizkid
|
||||||
|
burna boy
|
||||||
|
afcon
|
||||||
|
nollywood
|
||||||
@@ -1,3 +1,183 @@
|
|||||||
|
kaaba
|
||||||
|
mathieu van der poel
|
||||||
|
een miljard
|
||||||
|
p2000
|
||||||
|
james comey
|
||||||
|
helena bonham carter
|
||||||
|
bultrug timmy
|
||||||
|
george russell
|
||||||
|
openbaar vervoer
|
||||||
|
wayne mardle
|
||||||
|
europese unie
|
||||||
|
florence pugh
|
||||||
|
concert golden earring ahoy
|
||||||
|
de telegraaf
|
||||||
|
openai
|
||||||
|
crypto insiders
|
||||||
|
stefano domenicali
|
||||||
|
brand emmeloord
|
||||||
|
loosdrecht
|
||||||
|
taylor swift
|
||||||
|
militair
|
||||||
|
emma heesters
|
||||||
|
luik-bastenaken-luik
|
||||||
|
luilakken koningsdag
|
||||||
|
rusland
|
||||||
|
shakira
|
||||||
|
car rental
|
||||||
|
112 leiden
|
||||||
|
taxi
|
||||||
|
michael
|
||||||
|
passengers
|
||||||
|
finale wie is de mol
|
||||||
|
bourtange
|
||||||
|
marseille - nice
|
||||||
|
unchosen
|
||||||
|
prinses
|
||||||
|
sylvester stallone
|
||||||
|
28 years later
|
||||||
|
programma koningsdag 2026
|
||||||
|
milan - juventus
|
||||||
|
aryna sabalenka
|
||||||
|
fortuna
|
||||||
|
curacao
|
||||||
|
atlético madrid - ath. bilbao
|
||||||
|
digid solvinity
|
||||||
|
baywatch
|
||||||
|
boy kemper
|
||||||
|
donyell malen
|
||||||
|
twente - nec
|
||||||
|
afc champions league
|
||||||
|
wesley sonck
|
||||||
|
arnold schwarzenegger
|
||||||
|
devil wears prada
|
||||||
|
jagiellonia białystok – górnik zabrze
|
||||||
|
max verstappen redbull
|
||||||
|
mvv - top oss
|
||||||
|
energiecontract
|
||||||
|
real betis - real madrid
|
||||||
|
fc den bosch
|
||||||
|
maarten van rossem
|
||||||
|
jake paul
|
||||||
|
financiën
|
||||||
|
zonnepaneel
|
||||||
|
xrp
|
||||||
|
cyprus
|
||||||
|
verdachte
|
||||||
|
112 eerbeek
|
||||||
|
golden earring
|
||||||
|
sergiño dest
|
||||||
|
david wilcock
|
||||||
|
asiago
|
||||||
|
shownieuws
|
||||||
|
nijmegen
|
||||||
|
keira knightley
|
||||||
|
112 meldingen amsterdam
|
||||||
|
dierenmishandeling
|
||||||
|
112 amsterdam
|
||||||
|
freek rikkerink
|
||||||
|
poetin
|
||||||
|
atalanta - lazio
|
||||||
|
mr nobody against putin
|
||||||
|
club brugge - mechelen
|
||||||
|
frank hosmar
|
||||||
|
barcelona - celta
|
||||||
|
kees flodder
|
||||||
|
burnley - manchester city
|
||||||
|
lodewijk asscher
|
||||||
|
vallende sterren
|
||||||
|
guus meeuwis
|
||||||
|
hoofddorp
|
||||||
|
kaja kallas
|
||||||
|
politiek
|
||||||
|
stroomstoring amersfoort
|
||||||
|
solvinity digid
|
||||||
|
wout weghorst
|
||||||
|
jamie kames
|
||||||
|
bitvavo
|
||||||
|
box 3
|
||||||
|
ronde van de alpen
|
||||||
|
matthias uhl
|
||||||
|
taken film
|
||||||
|
robot
|
||||||
|
girona - real betis
|
||||||
|
real madryt – deportivo alaves
|
||||||
|
tbilisi
|
||||||
|
southampton - bristol city
|
||||||
|
vittoria guazzini
|
||||||
|
oppo find x9 ultra
|
||||||
|
real madrid - alavés
|
||||||
|
الريال ضد ألافيس
|
||||||
|
lecce - fiorentina
|
||||||
|
pogoda jutro
|
||||||
|
vierhouten
|
||||||
|
weather tomorrow
|
||||||
|
over mijn lijk 2026 overleden
|
||||||
|
crystal palace - west ham
|
||||||
|
f-16 fighting falcon
|
||||||
|
klagenfurt
|
||||||
|
italië
|
||||||
|
ruud gullit
|
||||||
|
perfil falso
|
||||||
|
psg - lyon
|
||||||
|
juventus - bologna
|
||||||
|
troy parrott
|
||||||
|
az - nec opstellingen
|
||||||
|
caroline tensen
|
||||||
|
asielbeleid
|
||||||
|
philippe sandler
|
||||||
|
keerbergen
|
||||||
|
peer koopmeiners
|
||||||
|
nederlands elftal
|
||||||
|
pogoń szczecin – lech poznań
|
||||||
|
stand premier league
|
||||||
|
bulgarije
|
||||||
|
chelsea - man utd
|
||||||
|
atlético madrid - real sociedad
|
||||||
|
xavi simons
|
||||||
|
ayase ueda
|
||||||
|
roma - atalanta
|
||||||
|
rtv noord
|
||||||
|
paraguay
|
||||||
|
sergio herman
|
||||||
|
fed
|
||||||
|
keuken kampioen
|
||||||
|
legia warszawa – zagłębie lubin
|
||||||
|
ripple
|
||||||
|
voorzitter fed
|
||||||
|
bahamas
|
||||||
|
overtreding
|
||||||
|
almere city
|
||||||
|
real betis
|
||||||
|
sean connery
|
||||||
|
l1 nieuws
|
||||||
|
ronaldinho
|
||||||
|
demi de boer
|
||||||
|
bondgenoten
|
||||||
|
frank masmeijer
|
||||||
|
real betis - braga
|
||||||
|
ethereum
|
||||||
|
aston villa - bologna
|
||||||
|
manuel neuer
|
||||||
|
neuer
|
||||||
|
olise
|
||||||
|
mbappe
|
||||||
|
sporting
|
||||||
|
live tv
|
||||||
|
bayern munchen
|
||||||
|
arda güler
|
||||||
|
ziggo
|
||||||
|
arda guler
|
||||||
|
netflix
|
||||||
|
frenkie de jong
|
||||||
|
kanye west
|
||||||
|
vandaag inside
|
||||||
|
at5
|
||||||
|
veroordeling
|
||||||
|
verenigde staten
|
||||||
|
alec baldwin
|
||||||
|
anna paulowna
|
||||||
|
şampiyonlar ligi
|
||||||
NOS Nieuws
|
NOS Nieuws
|
||||||
Buienradar
|
Buienradar
|
||||||
Rijksoverheid
|
Rijksoverheid
|
||||||
@@ -12,4 +192,4 @@ Amsterdam Weer
|
|||||||
Bol.com
|
Bol.com
|
||||||
Treinkaartjes NS
|
Treinkaartjes NS
|
||||||
PostNL
|
PostNL
|
||||||
Pathé
|
Pathé
|
||||||
|
|||||||
@@ -1,3 +1,180 @@
|
|||||||
|
oman vs nepal
|
||||||
|
primary 1
|
||||||
|
mapletree industrial trust
|
||||||
|
spurs vs trail blazers
|
||||||
|
knicks vs hawks
|
||||||
|
celtics vs 76ers
|
||||||
|
snake
|
||||||
|
marriage
|
||||||
|
san lorenzo vs santos
|
||||||
|
bankruptcy
|
||||||
|
诈骗
|
||||||
|
us-iran
|
||||||
|
flight
|
||||||
|
jeanette aw
|
||||||
|
jisoo
|
||||||
|
nuggets vs timberwolves
|
||||||
|
suns vs thunder
|
||||||
|
magic vs pistons
|
||||||
|
drug
|
||||||
|
jimmy kimmel
|
||||||
|
erika kirk
|
||||||
|
elon musk
|
||||||
|
hokkaido earthquake today
|
||||||
|
rockets vs lakers
|
||||||
|
labour day
|
||||||
|
angela palmares
|
||||||
|
76ers vs celtics
|
||||||
|
nba scores
|
||||||
|
chernobyl disaster
|
||||||
|
tengah garden residences
|
||||||
|
torino vs inter
|
||||||
|
dortmund vs sc freiburg
|
||||||
|
angkrish raghuvanshi
|
||||||
|
mohsin khan
|
||||||
|
running man
|
||||||
|
arsenal vs lyon
|
||||||
|
genoa vs como
|
||||||
|
kkr vs lsg
|
||||||
|
bwf
|
||||||
|
chelsea vs leeds
|
||||||
|
bologna vs roma
|
||||||
|
angers vs psg
|
||||||
|
giant octopus fossil
|
||||||
|
premier league standings
|
||||||
|
apple iphone fold
|
||||||
|
arsenal vs newcastle
|
||||||
|
man city vs southampton
|
||||||
|
bundesliga
|
||||||
|
israel iran war
|
||||||
|
freddie woodman
|
||||||
|
sunderland vs nottm forest
|
||||||
|
real betis vs real madrid
|
||||||
|
anne hathaway
|
||||||
|
michael jackson
|
||||||
|
sai sudharsan
|
||||||
|
madrid open
|
||||||
|
amd
|
||||||
|
gt vs rcb
|
||||||
|
ijooz
|
||||||
|
raghav chadha
|
||||||
|
darren wang
|
||||||
|
mukesh choudhary
|
||||||
|
danish malewar
|
||||||
|
tamil nadu election results
|
||||||
|
allah ghazanfar
|
||||||
|
peregrine falcon
|
||||||
|
airasia flight
|
||||||
|
arrest
|
||||||
|
hao mart singapore
|
||||||
|
kartik sharma
|
||||||
|
real salt lake vs inter miami
|
||||||
|
pistons vs magic
|
||||||
|
krisflyer
|
||||||
|
michael jackson biopic
|
||||||
|
新加坡
|
||||||
|
atalanta vs lazio
|
||||||
|
伯恩利 - 曼城
|
||||||
|
porto vs sporting
|
||||||
|
cdl directors resign millennium copthorne
|
||||||
|
tsla
|
||||||
|
leverkusen vs bayern
|
||||||
|
burnley vs man city
|
||||||
|
elche vs atlético madrid
|
||||||
|
psg vs nantes
|
||||||
|
al-nassr vs al ahli
|
||||||
|
changi
|
||||||
|
rr vs lsg
|
||||||
|
primary school
|
||||||
|
alexandra eala
|
||||||
|
tan su shan
|
||||||
|
sundaresh menon
|
||||||
|
moulin rouge musical singapore
|
||||||
|
south korea
|
||||||
|
step
|
||||||
|
gamba osaka vs avispa fukuoka
|
||||||
|
honor 600 pro
|
||||||
|
china shipyards oil tanker orders
|
||||||
|
coe
|
||||||
|
lebron james
|
||||||
|
real madrid vs alavés
|
||||||
|
brighton vs chelsea
|
||||||
|
nitish rana
|
||||||
|
earth day
|
||||||
|
michael movie
|
||||||
|
kevin warsh
|
||||||
|
srh vs dc
|
||||||
|
chinese aircraft carrier liaoning
|
||||||
|
andie chen
|
||||||
|
jesseca liu wins best actress
|
||||||
|
crystal palace vs west ham
|
||||||
|
grok
|
||||||
|
gemini
|
||||||
|
claude ai
|
||||||
|
gpt
|
||||||
|
ai
|
||||||
|
is chatgpt down
|
||||||
|
strait of hormuz news
|
||||||
|
mi vs gt
|
||||||
|
psg vs lyon
|
||||||
|
sporting vs benfica
|
||||||
|
bayern munich
|
||||||
|
pl
|
||||||
|
bangkok weather
|
||||||
|
starhub
|
||||||
|
廖子妤
|
||||||
|
曼城 - 阿森纳
|
||||||
|
bayern vs vfb stuttgart
|
||||||
|
英超
|
||||||
|
chelsea vs man united
|
||||||
|
perfect crown
|
||||||
|
ayush mhatre
|
||||||
|
sarfaraz khan
|
||||||
|
napoli vs lazio
|
||||||
|
tottenham vs brighton
|
||||||
|
abhishek sharma
|
||||||
|
tinie tempah
|
||||||
|
wrexham vs stoke city
|
||||||
|
sassuolo vs como
|
||||||
|
the straits times
|
||||||
|
india women vs south africa women
|
||||||
|
beef season 2
|
||||||
|
loyang valley
|
||||||
|
world cup 2026
|
||||||
|
afc champions league
|
||||||
|
hormuz
|
||||||
|
malacca strait
|
||||||
|
kkr vs gt
|
||||||
|
aston villa vs bologna
|
||||||
|
mumbai indians vs punjab kings standings
|
||||||
|
al sadd vs vissel kobe
|
||||||
|
amd share price
|
||||||
|
opus 4.7
|
||||||
|
pete hegseth
|
||||||
|
naman dhir
|
||||||
|
yen singapore dollar
|
||||||
|
mayank rawat
|
||||||
|
dji pocket 4
|
||||||
|
real madrid
|
||||||
|
al-nassr vs al-ettifaq
|
||||||
|
bayern vs real madrid
|
||||||
|
arsenal vs sporting
|
||||||
|
lucknow super giants vs royal challengers bengaluru standings
|
||||||
|
is claude down
|
||||||
|
claude
|
||||||
|
allbirds
|
||||||
|
red sea
|
||||||
|
rcb vs lsg
|
||||||
|
retirement
|
||||||
|
asia flights delays cancellations
|
||||||
|
suns vs trail blazers
|
||||||
|
johnny somali
|
||||||
|
bam adebayo
|
||||||
|
zhang linghe pursuit of jade
|
||||||
|
roman gofman
|
||||||
|
cruz azul vs lafc
|
||||||
|
ocbc
|
||||||
|
santos vs recoleta
|
||||||
atlético madrid vs barcelona
|
atlético madrid vs barcelona
|
||||||
ipl schedule
|
ipl schedule
|
||||||
liverpool vs psg
|
liverpool vs psg
|
||||||
@@ -21,20 +198,3 @@ new rolex 2026
|
|||||||
medical classification
|
medical classification
|
||||||
blasphemy law
|
blasphemy law
|
||||||
big bang coachella 2026
|
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
|
|
||||||
cpf board login
|
|
||||||
hdb bto launch updates
|
|
||||||
best chicken rice near me
|
|
||||||
public holidays sg
|
|
||||||
singpass login portal
|
|
||||||
changi airport flight status
|
|
||||||
iras tax filing
|
|
||||||
|
|||||||
171
data/keywords/kw_TW.txt
Normal file
171
data/keywords/kw_TW.txt
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
十銓科技
|
||||||
|
邱軍
|
||||||
|
股東會紀念品
|
||||||
|
佳必琪
|
||||||
|
勞動 節
|
||||||
|
鍾東錦
|
||||||
|
棒球
|
||||||
|
spurs vs trail blazers
|
||||||
|
8028
|
||||||
|
鄭嘉睿
|
||||||
|
spencer jones
|
||||||
|
張凌赫
|
||||||
|
山本由伸
|
||||||
|
陳德修
|
||||||
|
國巨
|
||||||
|
台玻
|
||||||
|
俠 盜 獵 車手 vi
|
||||||
|
晶豪科
|
||||||
|
無限城
|
||||||
|
謝淑薇
|
||||||
|
台中停電
|
||||||
|
公務員
|
||||||
|
停電
|
||||||
|
hito 流行音樂獎
|
||||||
|
國際珍奶日
|
||||||
|
台積電 內 鬼
|
||||||
|
日圓
|
||||||
|
佳能
|
||||||
|
聯電 股東 會 紀念品
|
||||||
|
張雪機車
|
||||||
|
航空
|
||||||
|
暴龍 對 騎士
|
||||||
|
王苡丞
|
||||||
|
遊戲
|
||||||
|
chelsea đấu với leeds
|
||||||
|
เชลซี พบ ลีดส์
|
||||||
|
聯發科技
|
||||||
|
詹姆士
|
||||||
|
田麗
|
||||||
|
token
|
||||||
|
兵工廠
|
||||||
|
魔術 對 活塞
|
||||||
|
arsenal đấu với newcastle
|
||||||
|
t.o.p.
|
||||||
|
吸血鬼爬行者
|
||||||
|
足總盃
|
||||||
|
arsenal vs newcastle
|
||||||
|
man city đấu với southampton
|
||||||
|
消費券
|
||||||
|
6187
|
||||||
|
cpo概念股
|
||||||
|
anaheim
|
||||||
|
iu
|
||||||
|
山口智子
|
||||||
|
蔡依珊
|
||||||
|
林岱安
|
||||||
|
michael jackson 電影
|
||||||
|
行動電源
|
||||||
|
地震
|
||||||
|
地震速報
|
||||||
|
宋祖兒
|
||||||
|
porter
|
||||||
|
謝京穎
|
||||||
|
德州儀器
|
||||||
|
台新綜合證券
|
||||||
|
希臘
|
||||||
|
費城半導體
|
||||||
|
mrvl
|
||||||
|
狄鶯
|
||||||
|
三星罷工
|
||||||
|
00981a
|
||||||
|
馬斯克
|
||||||
|
辛耘
|
||||||
|
宏碁股價
|
||||||
|
0056
|
||||||
|
2330
|
||||||
|
雷霆 對 太陽
|
||||||
|
0050股價
|
||||||
|
006208
|
||||||
|
景碩
|
||||||
|
女警陳芊雯
|
||||||
|
廢死聯盟
|
||||||
|
西甲
|
||||||
|
台灣積體電路製造
|
||||||
|
高頻寬 記憶 體
|
||||||
|
戴奧辛
|
||||||
|
3665
|
||||||
|
宋晟睿
|
||||||
|
黃 甘霖
|
||||||
|
劉家翔
|
||||||
|
王耿豪
|
||||||
|
王勝偉
|
||||||
|
009816
|
||||||
|
thời tiết ngày mai
|
||||||
|
明天的天氣
|
||||||
|
總部
|
||||||
|
美光科技
|
||||||
|
cpbl
|
||||||
|
中華職棒
|
||||||
|
中職
|
||||||
|
黃甘霖
|
||||||
|
軍 公教
|
||||||
|
6147
|
||||||
|
earth day
|
||||||
|
陳哲遠
|
||||||
|
台鐵
|
||||||
|
斯普拉遁 塗擊隊
|
||||||
|
麥可傑克森
|
||||||
|
神將彩券行
|
||||||
|
米可白
|
||||||
|
洪敬堯
|
||||||
|
華邦電子
|
||||||
|
柔美的細胞小將 3
|
||||||
|
底特律老虎
|
||||||
|
三 商 美邦
|
||||||
|
川 普
|
||||||
|
英雄聯盟
|
||||||
|
聯電adr
|
||||||
|
rklb
|
||||||
|
amd stock
|
||||||
|
宋仲基
|
||||||
|
德甲
|
||||||
|
塞爾提克 對 76人
|
||||||
|
justin bieber 演唱會
|
||||||
|
拜仁慕尼黑
|
||||||
|
何潤東
|
||||||
|
廖子妤
|
||||||
|
英超
|
||||||
|
許凱
|
||||||
|
tottenham vs brighton
|
||||||
|
長野縣
|
||||||
|
交通安全
|
||||||
|
朋友收集夢想生活
|
||||||
|
麥克傑克森
|
||||||
|
王濛
|
||||||
|
騎士 對 暴龍
|
||||||
|
熱刺 對 布萊頓
|
||||||
|
iem rio 2026
|
||||||
|
garret anderson
|
||||||
|
墓乃伊
|
||||||
|
曹格
|
||||||
|
claude design
|
||||||
|
柯文哲
|
||||||
|
金剛
|
||||||
|
荷 姆 茲 海峽
|
||||||
|
東北 季風
|
||||||
|
斯圖加特公開賽
|
||||||
|
歐聯
|
||||||
|
菡生婦幼診所
|
||||||
|
台鐵訂票
|
||||||
|
飛機
|
||||||
|
東光路
|
||||||
|
货币
|
||||||
|
amd
|
||||||
|
航空母艦
|
||||||
|
axti
|
||||||
|
Yahoo奇摩
|
||||||
|
天氣
|
||||||
|
蝦皮購物
|
||||||
|
PChome
|
||||||
|
Momo購物網
|
||||||
|
Mobile01
|
||||||
|
Dcard
|
||||||
|
巴哈姆特
|
||||||
|
中時電子報
|
||||||
|
聯合新聞網
|
||||||
|
台灣高鐵
|
||||||
|
台鐵時刻表
|
||||||
|
中華電信
|
||||||
|
統一發票
|
||||||
|
勞動部
|
||||||
@@ -1,3 +1,179 @@
|
|||||||
|
weather birmingham
|
||||||
|
bbc nees
|
||||||
|
ella langley
|
||||||
|
emma grede
|
||||||
|
ted lasso season 4 teaser trailer
|
||||||
|
antidepressants recall
|
||||||
|
financial crisis
|
||||||
|
itv news
|
||||||
|
engagement rings
|
||||||
|
spurs vs trail blazers
|
||||||
|
alexey mordashov
|
||||||
|
good morning
|
||||||
|
mortgage rates
|
||||||
|
wren kitchens
|
||||||
|
horoscope
|
||||||
|
nba scores
|
||||||
|
nhl scores
|
||||||
|
nuggets vs timberwolves
|
||||||
|
liverpool weather
|
||||||
|
todays weather
|
||||||
|
playstation plus
|
||||||
|
manchester weather
|
||||||
|
wordle hint
|
||||||
|
everton f.c.
|
||||||
|
dvla
|
||||||
|
snooker results
|
||||||
|
sports
|
||||||
|
delivery
|
||||||
|
ronnie o'sullivan
|
||||||
|
janet cleverly councillor reprimanded
|
||||||
|
criminal record
|
||||||
|
mark selby
|
||||||
|
avs vs sporting
|
||||||
|
david attenborough
|
||||||
|
juventus
|
||||||
|
elena rybakina
|
||||||
|
eric bana
|
||||||
|
roman kemp
|
||||||
|
house fire wolverhampton
|
||||||
|
paul merson
|
||||||
|
is scarlett moffatt pregnant
|
||||||
|
man city fixtures
|
||||||
|
scarlets vs bulls
|
||||||
|
bankruptcy
|
||||||
|
monaco fc
|
||||||
|
jaqueline cristian
|
||||||
|
stock market
|
||||||
|
napoli
|
||||||
|
alex de minaur
|
||||||
|
tigers vs hull fc
|
||||||
|
edinburgh vs sharks
|
||||||
|
mark williams snooker
|
||||||
|
alex sinclair israeli police detention
|
||||||
|
st. johnstone vs raith rovers
|
||||||
|
mo farah
|
||||||
|
newcastle vs bristol
|
||||||
|
tbilisi
|
||||||
|
connor storrie
|
||||||
|
georgia
|
||||||
|
stephen bunting
|
||||||
|
great british menu 2026
|
||||||
|
ravi eastenders
|
||||||
|
salford city fc
|
||||||
|
national grid
|
||||||
|
mass effect
|
||||||
|
salford city vs bromley
|
||||||
|
real salt lake vs inter miami
|
||||||
|
provinces of the pantheon
|
||||||
|
mls
|
||||||
|
russell brand
|
||||||
|
john phelan
|
||||||
|
hung cao
|
||||||
|
pistons vs magic
|
||||||
|
jerry bruckheimer
|
||||||
|
st. george's day
|
||||||
|
asiago
|
||||||
|
framework laptop 13 pro
|
||||||
|
boro
|
||||||
|
interactive investor
|
||||||
|
mint
|
||||||
|
believe me itv
|
||||||
|
amanda bynes
|
||||||
|
strasbourg vs nice
|
||||||
|
chase bank
|
||||||
|
jak jones
|
||||||
|
chase
|
||||||
|
rodri
|
||||||
|
christopher trybus
|
||||||
|
lsg vs rr
|
||||||
|
pension
|
||||||
|
hebden bridge
|
||||||
|
sandra bullock practical magic
|
||||||
|
rolls-royce share price drop
|
||||||
|
invincible season 5
|
||||||
|
josé mourinho
|
||||||
|
chris wakelin
|
||||||
|
jimmy bullard adam thomas
|
||||||
|
aer lingus flight cancellations
|
||||||
|
sam west
|
||||||
|
oxford united
|
||||||
|
liam delap
|
||||||
|
wba
|
||||||
|
реал мадрид – алавес
|
||||||
|
coppa italia
|
||||||
|
girona vs real betis
|
||||||
|
marcus rashford
|
||||||
|
الريال ضد ألافيس
|
||||||
|
supreme leader of iran
|
||||||
|
oscar isaac
|
||||||
|
xrp ledger
|
||||||
|
pablo
|
||||||
|
is tane leaving home and away
|
||||||
|
julie andrews
|
||||||
|
danny boyle
|
||||||
|
nina eastenders
|
||||||
|
john stones
|
||||||
|
amazon vega os fire tv
|
||||||
|
porto vs tondela
|
||||||
|
santos vs fluminense
|
||||||
|
martin brundle lost f1 seat
|
||||||
|
keegan bradley
|
||||||
|
antoni kowalski
|
||||||
|
kezia dugdale
|
||||||
|
car
|
||||||
|
beef netflix
|
||||||
|
juventus vs bologna
|
||||||
|
losc vs nice
|
||||||
|
david szalay
|
||||||
|
the killer
|
||||||
|
joe cole
|
||||||
|
lille fc
|
||||||
|
simon cowell
|
||||||
|
pl
|
||||||
|
frank lampard everton
|
||||||
|
nottingham forest fixtures
|
||||||
|
everton manager
|
||||||
|
dragons vs bulls
|
||||||
|
suede
|
||||||
|
lahore
|
||||||
|
wrestlemania 2026
|
||||||
|
giants vs rhinos
|
||||||
|
glenrothan
|
||||||
|
york knights vs leopards
|
||||||
|
tim sherwood
|
||||||
|
redditch
|
||||||
|
ccfc
|
||||||
|
europa conference league
|
||||||
|
bromley fc
|
||||||
|
paul merton
|
||||||
|
chris wood
|
||||||
|
istanbul
|
||||||
|
turkey
|
||||||
|
lucy watson
|
||||||
|
thiago silva
|
||||||
|
bednarek
|
||||||
|
jan bednarek
|
||||||
|
vincent kompany
|
||||||
|
mbappe
|
||||||
|
luis suarez sporting
|
||||||
|
madrid fc
|
||||||
|
andriy lunin
|
||||||
|
what did bec say to rachel mafs
|
||||||
|
yalla kora
|
||||||
|
geovany quenda
|
||||||
|
sporting cp
|
||||||
|
pavlovic
|
||||||
|
talktalk
|
||||||
|
arne slot drops mohamed salah
|
||||||
|
suns vs trail blazers
|
||||||
|
italian
|
||||||
|
used cars
|
||||||
|
mlb
|
||||||
|
roman
|
||||||
|
johnny somali
|
||||||
|
windows update
|
||||||
|
davion mitchell
|
||||||
hbo max
|
hbo max
|
||||||
bolton wanderers
|
bolton wanderers
|
||||||
barca vs atletico
|
barca vs atletico
|
||||||
@@ -22,19 +198,3 @@ tori amos
|
|||||||
cloud
|
cloud
|
||||||
reading
|
reading
|
||||||
rolls-royce smr
|
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
|
|
||||||
tesco near me
|
|
||||||
tube map london
|
|
||||||
uk bank holidays
|
|
||||||
royal family news
|
|
||||||
how to make english tea
|
|
||||||
nhs symptom checker
|
|
||||||
property for sale in london
|
|
||||||
|
|||||||
@@ -1,10 +1,191 @@
|
|||||||
|
acura
|
||||||
|
qatar airways
|
||||||
|
charles barkley
|
||||||
|
turkish airlines
|
||||||
|
ayo edebiri
|
||||||
|
who do the spurs play next
|
||||||
|
one championship
|
||||||
|
samsung one ui 8.5 update
|
||||||
|
fabio jackson
|
||||||
|
san antonio
|
||||||
|
shea theodore
|
||||||
|
dodgers game today
|
||||||
|
munetaka murakami
|
||||||
|
dodgers score
|
||||||
|
joe ingles
|
||||||
|
owensboro weather
|
||||||
|
nhl overtime rules
|
||||||
|
kyle tucker
|
||||||
|
pete fairbanks
|
||||||
|
bank
|
||||||
|
ucla
|
||||||
|
housing prices
|
||||||
|
real estate
|
||||||
|
post malone
|
||||||
|
ducks game tonight
|
||||||
|
flor vigna
|
||||||
|
lebron james
|
||||||
|
bronny james
|
||||||
|
austin shooting
|
||||||
|
arthur rinderknech
|
||||||
|
avs vs sporting
|
||||||
|
elena rybakina
|
||||||
|
chris sale
|
||||||
|
bruins
|
||||||
|
sabres game
|
||||||
|
corinthians vs vasco
|
||||||
|
christian walker
|
||||||
|
where to watch new york yankees vs houston astros
|
||||||
|
gladiator ii
|
||||||
|
hurricanes vs senators
|
||||||
|
jalen duren
|
||||||
|
keegan akin
|
||||||
|
billy schrauth
|
||||||
|
caleb durbin
|
||||||
|
thunder vs suns
|
||||||
|
max bredeson
|
||||||
|
wednesday, season 3
|
||||||
|
demonte capehart
|
||||||
|
karoline leavitt maternity leave
|
||||||
|
alex de minaur
|
||||||
|
rafael jodar
|
||||||
|
adam levine face
|
||||||
|
howard frankland bridge
|
||||||
|
vibrio vulnificus new york waters
|
||||||
|
stade brestois - lens
|
||||||
|
moustapha thiam
|
||||||
|
us asylum seeker border reopening
|
||||||
|
sunderland vs nottm forest
|
||||||
|
leicester city vs millwall
|
||||||
|
brandon marsh
|
||||||
|
psv vs pec zwolle
|
||||||
|
daniel merida aguilar
|
||||||
|
william byron
|
||||||
|
eve plumb
|
||||||
|
mall of louisiana
|
||||||
|
real oviedo vs villarreal
|
||||||
|
real oviedo - villarreal
|
||||||
|
call of duty: black ops 7
|
||||||
|
tarik skubal
|
||||||
|
cubs game today
|
||||||
|
mike repole
|
||||||
|
okc thunder
|
||||||
|
atlanta braves
|
||||||
|
mlb scores today
|
||||||
|
braves standings
|
||||||
|
kevin mckidd
|
||||||
|
dan vladar
|
||||||
|
mls standings
|
||||||
|
dodgers - giants
|
||||||
|
jon ossoff
|
||||||
|
ozzy survivor
|
||||||
|
braves score
|
||||||
|
washington nationals
|
||||||
|
alex bregman
|
||||||
|
peter lambert
|
||||||
|
darrell sheets
|
||||||
|
ludwig kaiser
|
||||||
|
edina shooting
|
||||||
|
atalanta - lazio
|
||||||
|
barcelona vs celta vigo
|
||||||
|
rivian r2
|
||||||
|
pick 4
|
||||||
|
aoc
|
||||||
|
cleveland browns
|
||||||
|
nintendo switch gamecube games
|
||||||
|
lsg vs rr
|
||||||
|
spirit
|
||||||
|
atlanta fire
|
||||||
|
deshaun watson
|
||||||
|
good morning america
|
||||||
|
pittsburgh
|
||||||
|
strands answers
|
||||||
|
scientist
|
||||||
|
mark cuban pharmacy
|
||||||
|
inter milan
|
||||||
|
lens vs toulouse
|
||||||
|
david james
|
||||||
|
andy weir
|
||||||
|
noah kahan tiny desk concert
|
||||||
|
jennifer garner 54th birthday photos
|
||||||
|
troy baker
|
||||||
|
real madrid - alavés
|
||||||
|
girona - real betis
|
||||||
|
girona vs real betis
|
||||||
|
arc raiders
|
||||||
|
schd etf dividend yield
|
||||||
|
deportación
|
||||||
|
lecce - fiorentina
|
||||||
|
valley forge high school
|
||||||
|
betty yee
|
||||||
|
seth trimble
|
||||||
|
bill belichick
|
||||||
|
winter storm
|
||||||
|
jim parsons
|
||||||
|
kings vs avalanche
|
||||||
|
suns vs thunder
|
||||||
|
wolf
|
||||||
|
santos - fluminense
|
||||||
|
mets - cubs
|
||||||
|
alexander manninger
|
||||||
|
santos vs fluminense
|
||||||
|
disclosure day
|
||||||
|
tobias myers
|
||||||
|
vladimir putin
|
||||||
|
knicks game
|
||||||
|
ben rice
|
||||||
|
prem
|
||||||
|
timberwolves vs nuggets
|
||||||
|
cody bellinger
|
||||||
|
nik khamenia
|
||||||
|
real sociedad
|
||||||
|
nurburgring crash
|
||||||
|
atlético madrid - real sociedad
|
||||||
|
ruke orhorhoro
|
||||||
|
radar
|
||||||
|
the weather channel
|
||||||
|
kttc
|
||||||
|
luke gulbranson
|
||||||
|
kttc weather
|
||||||
|
comcast data breach settlement
|
||||||
|
tornado watch
|
||||||
|
moisés ballesteros
|
||||||
|
mets game today
|
||||||
|
giancarlo stanton
|
||||||
|
real betis
|
||||||
|
prosecution of daniel duggan
|
||||||
|
liv morgan
|
||||||
|
mikey williams
|
||||||
|
indiana fever sophie cunningham baptism
|
||||||
|
gregory donnell morgan jr
|
||||||
|
why are the sirens going off
|
||||||
|
leylah fernandez
|
||||||
|
strasbourg vs mainz
|
||||||
|
michael olise
|
||||||
|
ريال مدريد
|
||||||
|
dazn
|
||||||
|
paramount
|
||||||
|
univision
|
||||||
|
jude bellingham
|
||||||
|
sam antonacci
|
||||||
|
real madrid
|
||||||
|
bayern
|
||||||
|
arda güler
|
||||||
|
los angeles dodgers
|
||||||
|
vandenberg launch schedule
|
||||||
|
ryan dunn
|
||||||
|
alex vesia
|
||||||
|
ken jennings
|
||||||
|
ucla baseball
|
||||||
|
padres standings
|
||||||
|
mets vs dodgers match player stats
|
||||||
|
bo bichette
|
||||||
|
jorge polanco
|
||||||
psg
|
psg
|
||||||
barca
|
barca
|
||||||
vix
|
vix
|
||||||
fcb
|
fcb
|
||||||
barcelona schedule
|
barcelona schedule
|
||||||
univision
|
|
||||||
paramount
|
|
||||||
tarjeta roja
|
tarjeta roja
|
||||||
a knight of the seven kingdoms season 2
|
a knight of the seven kingdoms season 2
|
||||||
charlotte flair
|
charlotte flair
|
||||||
@@ -17,23 +198,3 @@ levante - getafe
|
|||||||
levante vs getafe
|
levante vs getafe
|
||||||
mcilroy green jacket presentation
|
mcilroy green jacket presentation
|
||||||
man united vs leeds
|
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
|
|
||||||
latest tech news
|
|
||||||
California traffic updates
|
|
||||||
AI startups in Silicon ValleySan Jose weather this weekend
|
|
||||||
Silicon Valley tech news
|
|
||||||
best tacos in San Jose
|
|
||||||
Apple park visitor center hours
|
|
||||||
|
|||||||
@@ -1,3 +1,179 @@
|
|||||||
|
giáp
|
||||||
|
nguyễn đình bắc
|
||||||
|
avispa đấu với sanfrecce
|
||||||
|
thừa kế
|
||||||
|
hoa hậu việt nam
|
||||||
|
nguyễn xuân bắc
|
||||||
|
áp thấp nhiệt đới
|
||||||
|
tàu
|
||||||
|
nte code
|
||||||
|
bảo tín minh châu
|
||||||
|
cà phê
|
||||||
|
one ui 8.5
|
||||||
|
nguyễn huy hoàng
|
||||||
|
dự án nuôi em
|
||||||
|
đơn vị sự nghiệp công lập
|
||||||
|
nợ xấu
|
||||||
|
bộ trưởng bộ giáo dục và đào tạo việt nam
|
||||||
|
thành phố trực thuộc trung ương
|
||||||
|
âm vang tổ quốc
|
||||||
|
jennie
|
||||||
|
charlie nguyễn
|
||||||
|
nanaimoteuthis
|
||||||
|
cảng
|
||||||
|
vneid
|
||||||
|
sri lanka
|
||||||
|
công nhân
|
||||||
|
hội đồng giám mục việt nam
|
||||||
|
an ninh kinh tế
|
||||||
|
kfc
|
||||||
|
đội tuyển bóng chuyền nữ quốc gia việt nam
|
||||||
|
juventus
|
||||||
|
milan đấu với juventus
|
||||||
|
villarreal đấu với celta
|
||||||
|
osasuna vs sevilla
|
||||||
|
galatasaray
|
||||||
|
michael jackson
|
||||||
|
sevilla
|
||||||
|
polymarket
|
||||||
|
mật ngữ kỷ
|
||||||
|
osasuna đấu với sevilla
|
||||||
|
atlético madrid đấu với ath. bilbao
|
||||||
|
erling haaland
|
||||||
|
lịch thi đấu man city
|
||||||
|
toulouse đấu với monaco
|
||||||
|
mc vs
|
||||||
|
đông anh
|
||||||
|
al ahli
|
||||||
|
man city
|
||||||
|
chung cư
|
||||||
|
napoli
|
||||||
|
sunderland đấu với nottm forest
|
||||||
|
betis đấu với real madrid
|
||||||
|
napoli đấu với cremonese
|
||||||
|
leipzig đấu với union berlin
|
||||||
|
sunderland
|
||||||
|
mẫu iphone 18
|
||||||
|
oppo find x9 ultra
|
||||||
|
xem phim
|
||||||
|
andoni iraola
|
||||||
|
stuttgart đấu với freiburg
|
||||||
|
levante – sevilla
|
||||||
|
giao dịch tài chính
|
||||||
|
rayo đấu với espanyol
|
||||||
|
levante đấu với sevilla
|
||||||
|
bong ma hanh phuc
|
||||||
|
aryna sabalenka
|
||||||
|
mason nguyễn
|
||||||
|
marcus rashford
|
||||||
|
hà nội
|
||||||
|
salt lake đấu với inter miami
|
||||||
|
hung cao
|
||||||
|
neymar
|
||||||
|
cầu phú mỹ
|
||||||
|
nhac
|
||||||
|
wordle
|
||||||
|
날씨
|
||||||
|
giá cà phê hôm nay
|
||||||
|
premier league standings
|
||||||
|
mls
|
||||||
|
phạm nhật vượng
|
||||||
|
cristiano roland
|
||||||
|
burnley vs man city
|
||||||
|
bayern munich
|
||||||
|
atalanta đấu với lazio
|
||||||
|
barcelona đấu với celta
|
||||||
|
psg – nantes
|
||||||
|
leverkusen đấu với bayern
|
||||||
|
elche – atlético madrid
|
||||||
|
bryan mbeumo
|
||||||
|
al nasr
|
||||||
|
trực tiếp bóng đá hôm nay
|
||||||
|
vtv3
|
||||||
|
vtv3 trực tiếp
|
||||||
|
tv
|
||||||
|
vtv
|
||||||
|
vtv6
|
||||||
|
360
|
||||||
|
lê khánh
|
||||||
|
ô tô
|
||||||
|
lê phương
|
||||||
|
trực tiếp bóng đá u17 hôm nay
|
||||||
|
inter milan
|
||||||
|
chelsea
|
||||||
|
girona đấu với betis
|
||||||
|
real madrid đấu với alavés
|
||||||
|
brighton vs chelsea
|
||||||
|
brighton đấu với chelsea
|
||||||
|
ath. bilbao đấu với osasuna
|
||||||
|
pep guardiola
|
||||||
|
zelvia đấu với shabab al-ahli
|
||||||
|
cầu thủ
|
||||||
|
lecce vs fiorentina
|
||||||
|
fiorentina
|
||||||
|
crystal palace đấu với west ham
|
||||||
|
afc champions league
|
||||||
|
eduardo camavinga
|
||||||
|
vissel kobe
|
||||||
|
gemi
|
||||||
|
idp
|
||||||
|
bảo hiểm y tế
|
||||||
|
crystal palace vs west ham
|
||||||
|
sporting lisbon
|
||||||
|
psg vs lyon
|
||||||
|
ca sĩ
|
||||||
|
juventus đấu với bologna
|
||||||
|
gladbach đấu với mainz
|
||||||
|
twitch
|
||||||
|
psg đấu với lyon
|
||||||
|
ligue 1
|
||||||
|
trận đấu ngoại hạng anh
|
||||||
|
chelsea đấu với man utd
|
||||||
|
atlético madrid đấu với real sociedad
|
||||||
|
roma đấu với atalanta
|
||||||
|
epl
|
||||||
|
iem rio 2026
|
||||||
|
tot
|
||||||
|
tập đoàn gelex
|
||||||
|
đường ray
|
||||||
|
inter
|
||||||
|
inter đấu với cagliari
|
||||||
|
sassuolo vs como
|
||||||
|
david alaba
|
||||||
|
claude design
|
||||||
|
fenerbahçe đấu với rizespor
|
||||||
|
como
|
||||||
|
como vs
|
||||||
|
thẻ đỏ
|
||||||
|
porto vs
|
||||||
|
crystal palace
|
||||||
|
porto
|
||||||
|
uefa europa conference
|
||||||
|
betis đấu với braga
|
||||||
|
real betis vs braga
|
||||||
|
aston villa đấu với bologna
|
||||||
|
fiorentina đấu với crystal palace
|
||||||
|
c2
|
||||||
|
cup c2
|
||||||
|
thể thao
|
||||||
|
arda güler
|
||||||
|
aleksandar pavlović
|
||||||
|
ars
|
||||||
|
90
|
||||||
|
real
|
||||||
|
real madrid
|
||||||
|
xoi
|
||||||
|
luong sơn
|
||||||
|
fpt
|
||||||
|
phan văn giang
|
||||||
|
nhà ở xã hội
|
||||||
|
club america
|
||||||
|
giàu
|
||||||
|
đỗ mỹ linh
|
||||||
|
sun group
|
||||||
|
hưng yên
|
||||||
|
nvl
|
||||||
|
américa đấu với nashville
|
||||||
VnExpress
|
VnExpress
|
||||||
Zing News
|
Zing News
|
||||||
Thời tiết Hà Nội
|
Thời tiết Hà Nội
|
||||||
|
|||||||
285
data/map.json
285
data/map.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "3.5.0",
|
"version": "3.5.2",
|
||||||
"updated_at": "2026-04-15",
|
"updated_at": "2026-04-19",
|
||||||
"continents": [
|
"continents": [
|
||||||
{
|
{
|
||||||
"id": "ASIA",
|
"id": "ASIA",
|
||||||
@@ -15,7 +15,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Tokyo", "name": "Tokyo (东京)" }
|
{
|
||||||
|
"id": "Tokyo",
|
||||||
|
"name": "Tokyo (东京)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -29,7 +32,27 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Singapore", "name": "Singapore (新加坡)" }
|
{
|
||||||
|
"id": "Singapore",
|
||||||
|
"name": "Singapore (新加坡)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "KR",
|
||||||
|
"name": "South Korea (韩国)",
|
||||||
|
"keyword_file": "kw_KR.txt",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "Default",
|
||||||
|
"name": "Default State",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Seoul",
|
||||||
|
"name": "Seoul (首尔)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -43,7 +66,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "HongKong", "name": "Hong Kong (香港)" }
|
{
|
||||||
|
"id": "HongKong",
|
||||||
|
"name": "Hong Kong (香港)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -57,7 +83,44 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Hanoi", "name": "Hanoi (河内)" }
|
{
|
||||||
|
"id": "Hanoi",
|
||||||
|
"name": "Hanoi (河内)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TW",
|
||||||
|
"name": "Taiwan (台湾)",
|
||||||
|
"keyword_file": "kw_TW.txt",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "Default",
|
||||||
|
"name": "Default State",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Taipei",
|
||||||
|
"name": "Taipei (台北)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "MY",
|
||||||
|
"name": "Malaysia (马来西亚)",
|
||||||
|
"keyword_file": "kw_MY.txt",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "Default",
|
||||||
|
"name": "Default State",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Kuala_Lumpur",
|
||||||
|
"name": "Kuala Lumpur (吉隆坡)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -77,7 +140,14 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "London", "name": "London (伦敦)" }
|
{
|
||||||
|
"id": "London",
|
||||||
|
"name": "London (伦敦)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Coventry",
|
||||||
|
"name": "Coventry (考文垂)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -91,7 +161,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Frankfurt", "name": "Frankfurt (法兰克福)" }
|
{
|
||||||
|
"id": "Frankfurt",
|
||||||
|
"name": "Frankfurt (法兰克福)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -105,7 +178,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Paris", "name": "Paris (巴黎)" }
|
{
|
||||||
|
"id": "Paris",
|
||||||
|
"name": "Paris (巴黎)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -119,7 +195,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Amsterdam", "name": "Amsterdam (阿姆斯特丹)" }
|
{
|
||||||
|
"id": "Amsterdam",
|
||||||
|
"name": "Amsterdam (阿姆斯特丹)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -133,7 +212,10 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Madrid", "name": "Madrid (马德里)" }
|
{
|
||||||
|
"id": "Madrid",
|
||||||
|
"name": "Madrid (马德里)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -153,8 +235,88 @@
|
|||||||
"id": "CA",
|
"id": "CA",
|
||||||
"name": "California (加州)",
|
"name": "California (加州)",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Los_Angeles", "name": "Los Angeles (洛杉矶)" },
|
{
|
||||||
{ "id": "San_Jose", "name": "San Jose (圣何塞)" }
|
"id": "Los_Angeles",
|
||||||
|
"name": "Los Angeles (洛杉矶)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "San_Jose",
|
||||||
|
"name": "San Jose (圣何塞)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "IL",
|
||||||
|
"name": "Illinois (伊利诺伊州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Warrenville",
|
||||||
|
"name": "Warrenville (沃伦维尔)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "NC",
|
||||||
|
"name": "North Carolina (北卡罗来纳州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Charlotte",
|
||||||
|
"name": "Charlotte (夏洛特)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "NV",
|
||||||
|
"name": "Nevada (内华达州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Las_Vegas",
|
||||||
|
"name": "Las Vegas (拉斯维加斯)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "OR",
|
||||||
|
"name": "Oregon (俄勒冈州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Bend",
|
||||||
|
"name": "Bend (本德)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "UT",
|
||||||
|
"name": "Utah (犹他州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Salt_Lake_City",
|
||||||
|
"name": "Salt Lake City (盐湖城)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "WA",
|
||||||
|
"name": "Washington (华盛顿州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Seattle",
|
||||||
|
"name": "Seattle (西雅图)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "TX",
|
||||||
|
"name": "Texas (得克萨斯州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Dallas",
|
||||||
|
"name": "Dallas (达拉斯)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Houston",
|
||||||
|
"name": "Houston (休斯顿)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -168,7 +330,100 @@
|
|||||||
"id": "Default",
|
"id": "Default",
|
||||||
"name": "Default State",
|
"name": "Default State",
|
||||||
"cities": [
|
"cities": [
|
||||||
{ "id": "Toronto", "name": "Toronto (多伦多)" }
|
{
|
||||||
|
"id": "Toronto",
|
||||||
|
"name": "Toronto (多伦多)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Montreal",
|
||||||
|
"name": "Montreal (蒙特利尔)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "OCEANIA",
|
||||||
|
"name": "大洋洲战区 (Oceania)",
|
||||||
|
"countries": [
|
||||||
|
{
|
||||||
|
"id": "AU",
|
||||||
|
"name": "Australia (澳大利亚)",
|
||||||
|
"keyword_file": "kw_AU.txt",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "NSW",
|
||||||
|
"name": "New South Wales (新南威尔士州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Sydney",
|
||||||
|
"name": "Sydney (悉尼)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "VIC",
|
||||||
|
"name": "Victoria (维多利亚州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Melbourne",
|
||||||
|
"name": "Melbourne (墨尔本)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "QLD",
|
||||||
|
"name": "Queensland (昆士兰州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Brisbane",
|
||||||
|
"name": "Brisbane (布里斯班)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "WA",
|
||||||
|
"name": "Western Australia (西澳大利亚州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Perth",
|
||||||
|
"name": "Perth (珀斯)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "SA",
|
||||||
|
"name": "South Australia (南澳大利亚州)",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Adelaide",
|
||||||
|
"name": "Adelaide (阿德莱德)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "AFRICA",
|
||||||
|
"name": "非洲战区 (Africa)",
|
||||||
|
"countries": [
|
||||||
|
{
|
||||||
|
"id": "NG",
|
||||||
|
"name": "Nigeria (尼日利亚)",
|
||||||
|
"keyword_file": "kw_NG.txt",
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"id": "Default",
|
||||||
|
"name": "Default State",
|
||||||
|
"cities": [
|
||||||
|
{
|
||||||
|
"id": "Lagos",
|
||||||
|
"name": "Lagos (拉各斯)"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -176,4 +431,4 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
50
data/regions/AU/NSW/Sydney.json
Normal file
50
data/regions/AU/NSW/Sydney.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Australia - Sydney",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": -33.8697,
|
||||||
|
"base_lon": 151.2085,
|
||||||
|
"lang_params": "hl=en-AU&gl=AU",
|
||||||
|
"valid_url_suffix": "com.au"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/what-should-schools-do-about-ai-deepfakes-friends-school-hobart/106619686",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/monthly-inflation-surges-in-march-australia/106619740",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/afl-pushes-ahead-with-draft-changes-and-not-everyone-is-happy/106621516",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/inflation-details-may-give-rba-pause-on-interest-rates/106620164",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/gina-rinehart-gifts-plane-to-pauline-hanson-one-nation/106620808",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/plane-crashes-at-parafield-airport-north-of-adelaide/106621632",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/toddler-death-northern-beaches-hospital-public-ownership/106620104",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-man-charged-hate-speech-laws-not-guilty-pleas/106619998",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-cfmeu-inquiry-ravbar-lazy-alleged-threats-bruce-highway/106620854",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/knife-produced-mental-health-patient-not-found-act-police/106619254",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/chilcare-group-g8-to-close-10-per-cent-of-centres/106620512",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/keith-lees-court-cold-case-committal-hearing-sunshine-coast/106619782",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/ancient-platypus-fossils-with-teeth-found-outback-sa/106616134",
|
||||||
|
"https://www.bunnings.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/nsw-state-of-origin-womens-queensland-maroons/106621490",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/mlb-australia-travis-bazzana-makes-cleveland-guardians-debut/106620048",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.commbank.com.au/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/AU/QLD/Brisbane.json
Normal file
50
data/regions/AU/QLD/Brisbane.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Australia - Brisbane",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": -27.4697,
|
||||||
|
"base_lon": 153.0252,
|
||||||
|
"lang_params": "hl=en-AU&gl=AU",
|
||||||
|
"valid_url_suffix": "com.au"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/plane-crashes-at-parafield-airport-north-of-adelaide/106621632",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/chilcare-group-g8-to-close-10-per-cent-of-centres/106620512",
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/what-should-schools-do-about-ai-deepfakes-friends-school-hobart/106619686",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/ancient-platypus-fossils-with-teeth-found-outback-sa/106616134",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/mlb-australia-travis-bazzana-makes-cleveland-guardians-debut/106620048",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/afl-pushes-ahead-with-draft-changes-and-not-everyone-is-happy/106621516",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/nsw-state-of-origin-womens-queensland-maroons/106621490",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-man-charged-hate-speech-laws-not-guilty-pleas/106619998",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/toddler-death-northern-beaches-hospital-public-ownership/106620104",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/monthly-inflation-surges-in-march-australia/106619740",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/inflation-details-may-give-rba-pause-on-interest-rates/106620164",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/knife-produced-mental-health-patient-not-found-act-police/106619254",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/gina-rinehart-gifts-plane-to-pauline-hanson-one-nation/106620808",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-cfmeu-inquiry-ravbar-lazy-alleged-threats-bruce-highway/106620854",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/keith-lees-court-cold-case-committal-hearing-sunshine-coast/106619782",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/AU/SA/Adelaide.json
Normal file
50
data/regions/AU/SA/Adelaide.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Australia - Adelaide",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": -34.9227,
|
||||||
|
"base_lon": 138.6016,
|
||||||
|
"lang_params": "hl=en-AU&gl=AU",
|
||||||
|
"valid_url_suffix": "com.au"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/nsw-state-of-origin-womens-queensland-maroons/106621490",
|
||||||
|
"https://www.bunnings.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/keith-lees-court-cold-case-committal-hearing-sunshine-coast/106619782",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/gina-rinehart-gifts-plane-to-pauline-hanson-one-nation/106620808",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/plane-crashes-at-parafield-airport-north-of-adelaide/106621632",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/monthly-inflation-surges-in-march-australia/106619740",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/afl-pushes-ahead-with-draft-changes-and-not-everyone-is-happy/106621516",
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/what-should-schools-do-about-ai-deepfakes-friends-school-hobart/106619686",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/inflation-details-may-give-rba-pause-on-interest-rates/106620164",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/knife-produced-mental-health-patient-not-found-act-police/106619254",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/ancient-platypus-fossils-with-teeth-found-outback-sa/106616134",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/toddler-death-northern-beaches-hospital-public-ownership/106620104",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-man-charged-hate-speech-laws-not-guilty-pleas/106619998",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/mlb-australia-travis-bazzana-makes-cleveland-guardians-debut/106620048",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-cfmeu-inquiry-ravbar-lazy-alleged-threats-bruce-highway/106620854",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/chilcare-group-g8-to-close-10-per-cent-of-centres/106620512"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/AU/VIC/Melbourne.json
Normal file
50
data/regions/AU/VIC/Melbourne.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Australia - Melbourne",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": -37.8106,
|
||||||
|
"base_lon": 144.9624,
|
||||||
|
"lang_params": "hl=en-AU&gl=AU",
|
||||||
|
"valid_url_suffix": "com.au"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/mlb-australia-travis-bazzana-makes-cleveland-guardians-debut/106620048",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/chilcare-group-g8-to-close-10-per-cent-of-centres/106620512",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-man-charged-hate-speech-laws-not-guilty-pleas/106619998",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/toddler-death-northern-beaches-hospital-public-ownership/106620104",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/keith-lees-court-cold-case-committal-hearing-sunshine-coast/106619782",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/what-should-schools-do-about-ai-deepfakes-friends-school-hobart/106619686",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-cfmeu-inquiry-ravbar-lazy-alleged-threats-bruce-highway/106620854",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/ancient-platypus-fossils-with-teeth-found-outback-sa/106616134",
|
||||||
|
"https://www.bunnings.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/inflation-details-may-give-rba-pause-on-interest-rates/106620164",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/plane-crashes-at-parafield-airport-north-of-adelaide/106621632",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/nsw-state-of-origin-womens-queensland-maroons/106621490",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/knife-produced-mental-health-patient-not-found-act-police/106619254",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/afl-pushes-ahead-with-draft-changes-and-not-everyone-is-happy/106621516",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/gina-rinehart-gifts-plane-to-pauline-hanson-one-nation/106620808",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/monthly-inflation-surges-in-march-australia/106619740"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/AU/WA/Perth.json
Normal file
50
data/regions/AU/WA/Perth.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Australia - Perth",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": -31.9545,
|
||||||
|
"base_lon": 115.8582,
|
||||||
|
"lang_params": "hl=en-AU&gl=AU",
|
||||||
|
"valid_url_suffix": "com.au"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/mlb-australia-travis-bazzana-makes-cleveland-guardians-debut/106620048",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/ancient-platypus-fossils-with-teeth-found-outback-sa/106616134",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/gina-rinehart-gifts-plane-to-pauline-hanson-one-nation/106620808",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/chilcare-group-g8-to-close-10-per-cent-of-centres/106620512",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/what-should-schools-do-about-ai-deepfakes-friends-school-hobart/106619686",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/knife-produced-mental-health-patient-not-found-act-police/106619254",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/monthly-inflation-surges-in-march-australia/106619740",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-cfmeu-inquiry-ravbar-lazy-alleged-threats-bruce-highway/106620854",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/keith-lees-court-cold-case-committal-hearing-sunshine-coast/106619782",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/toddler-death-northern-beaches-hospital-public-ownership/106620104",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/plane-crashes-at-parafield-airport-north-of-adelaide/106621632",
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.bunnings.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/qld-man-charged-hate-speech-laws-not-guilty-pleas/106619998",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/inflation-details-may-give-rba-pause-on-interest-rates/106620164",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/afl-pushes-ahead-with-draft-changes-and-not-everyone-is-happy/106621516",
|
||||||
|
"https://www.abc.net.au/news/2026-04-29/nsw-state-of-origin-womens-queensland-maroons/106621490"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://my.gov.au/",
|
||||||
|
"https://www.ato.gov.au/",
|
||||||
|
"https://www.bom.gov.au/",
|
||||||
|
"https://www.commbank.com.au/",
|
||||||
|
"https://www.seek.com.au/",
|
||||||
|
"https://www.realestate.com.au/",
|
||||||
|
"https://www.woolworths.com.au/",
|
||||||
|
"https://www.coles.com.au/",
|
||||||
|
"https://www.amazon.com.au/",
|
||||||
|
"https://www.bunnings.com.au/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
46
data/regions/CA/Default/Montreal.json
Normal file
46
data/regions/CA/Default/Montreal.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Canada - Montreal",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 45.5017,
|
||||||
|
"base_lon": -73.5673,
|
||||||
|
"lang_params": "hl=en&gl=CA",
|
||||||
|
"valid_url_suffix": "ca"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cbc.ca/news/world/san-francisco-oakland-airport-name-legal-case-9.7180726?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/manitoba/wolseley-hole-fix-repairs-9.7180881?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/world/us-intelligence-agencies-trump-iran-war-9.7180533?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/calgary/frances-widdowson-university-of-lethbridge-9.7180156?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/politics/carney-poilievre-carney-update-deficit-analysis-9.7180486?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/british-columbia/pentiction-councillor-trial-9.7180534?cmp=rss",
|
||||||
|
"https://www.td.com/",
|
||||||
|
"https://www.cbc.ca/news/politics/mail-searches-seu-9.7180828?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/world/trump-ballroom-justice-dept-federal-court-motion-9.7180270?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/calgary/janet-brown-poll-ucp-danielle-smith-road-ahead-9.7177527?cmp=rss",
|
||||||
|
"https://www.theweathernetwork.com/ca",
|
||||||
|
"https://www.amazon.ca/",
|
||||||
|
"https://www.cbc.ca/news/world/livestory/king-charles-us-state-visit-9.7178240?cmp=rss",
|
||||||
|
"https://www.canadapost-postescanada.ca/",
|
||||||
|
"https://www.cbc.ca/news/entertainment/trump-kimmel-melania-expectant-widow-9.7179036?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/world/ukraine-russia-refinery-attack-oil-prices-9.7180258?cmp=rss",
|
||||||
|
"https://www.utoronto.ca/",
|
||||||
|
"https://www.cbc.ca/player/play/9.7180775?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/saskatchewan/tow-truck-driver-rescues-moose-trapped-in-ice-9.7180811?cmp=rss",
|
||||||
|
"https://www.cra-arc.gc.ca/",
|
||||||
|
"https://www.rbcroyalbank.com/",
|
||||||
|
"https://www.canada.ca/en.html",
|
||||||
|
"https://www.cbc.ca/news/world/comey-indictment-blanche-shells-9.7180391?cmp=rss"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.canada.ca/en.html",
|
||||||
|
"https://www.cra-arc.gc.ca/",
|
||||||
|
"https://www.canadapost-postescanada.ca/",
|
||||||
|
"https://www.utoronto.ca/",
|
||||||
|
"https://www.td.com/",
|
||||||
|
"https://www.rbcroyalbank.com/",
|
||||||
|
"https://www.amazon.ca/",
|
||||||
|
"https://www.theweathernetwork.com/ca"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,13 +8,39 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://en.wikipedia.org/wiki/Special:Random",
|
"https://www.cbc.ca/news/canada/british-columbia/pentiction-councillor-trial-9.7180534?cmp=rss",
|
||||||
"https://www.canada.ca/en.html",
|
"https://www.cbc.ca/news/entertainment/trump-kimmel-melania-expectant-widow-9.7179036?cmp=rss",
|
||||||
"https://www.cbc.ca/",
|
"https://www.cbc.ca/news/world/comey-indictment-blanche-shells-9.7180391?cmp=rss",
|
||||||
"https://www.thestar.com/",
|
"https://www.cbc.ca/news/world/san-francisco-oakland-airport-name-legal-case-9.7180726?cmp=rss",
|
||||||
"https://www.ctvnews.ca/",
|
"https://www.cra-arc.gc.ca/",
|
||||||
|
"https://www.cbc.ca/news/politics/mail-searches-seu-9.7180828?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/politics/carney-poilievre-carney-update-deficit-analysis-9.7180486?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/calgary/janet-brown-poll-ucp-danielle-smith-road-ahead-9.7177527?cmp=rss",
|
||||||
"https://www.canadapost-postescanada.ca/",
|
"https://www.canadapost-postescanada.ca/",
|
||||||
"https://www.td.com/"
|
"https://www.cbc.ca/news/canada/calgary/frances-widdowson-university-of-lethbridge-9.7180156?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/world/livestory/king-charles-us-state-visit-9.7178240?cmp=rss",
|
||||||
|
"https://www.cbc.ca/player/play/9.7180775?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/world/trump-ballroom-justice-dept-federal-court-motion-9.7180270?cmp=rss",
|
||||||
|
"https://www.cbc.ca/news/canada/saskatchewan/tow-truck-driver-rescues-moose-trapped-in-ice-9.7180811?cmp=rss",
|
||||||
|
"https://www.rbcroyalbank.com/",
|
||||||
|
"https://www.td.com/",
|
||||||
|
"https://www.utoronto.ca/",
|
||||||
|
"https://www.cbc.ca/news/canada/manitoba/wolseley-hole-fix-repairs-9.7180881?cmp=rss",
|
||||||
|
"https://www.amazon.ca/",
|
||||||
|
"https://www.cbc.ca/news/world/ukraine-russia-refinery-attack-oil-prices-9.7180258?cmp=rss",
|
||||||
|
"https://www.canada.ca/en.html",
|
||||||
|
"https://www.cbc.ca/news/world/us-intelligence-agencies-trump-iran-war-9.7180533?cmp=rss",
|
||||||
|
"https://www.theweathernetwork.com/ca"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.canada.ca/en.html",
|
||||||
|
"https://www.cra-arc.gc.ca/",
|
||||||
|
"https://www.canadapost-postescanada.ca/",
|
||||||
|
"https://www.utoronto.ca/",
|
||||||
|
"https://www.td.com/",
|
||||||
|
"https://www.rbcroyalbank.com/",
|
||||||
|
"https://www.amazon.ca/",
|
||||||
|
"https://www.theweathernetwork.com/ca"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,39 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://www.amazon.de/",
|
"https://www.tagesschau.de/inland/unionsklausur-102.html",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/finanzen/marktbericht-schwerpunkt-oel-100.html",
|
||||||
|
"https://www.bundesregierung.de/",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/finanzen/marktberichte/marktbericht-134.html",
|
||||||
|
"https://www.tagesschau.de/ausland/europa/grossbritannien-starmer-untersuchung-mandelson-100.html",
|
||||||
|
"https://www.arbeitsagentur.de/",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/verbraucher/pkv-gkv-wechsel-100.html",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/unternehmen/bmw-lackiererei-industriejobs-100.html",
|
||||||
|
"https://www.tagesschau.de/ausland/amerika/trump-kritik-merz-iran-100.html",
|
||||||
|
"https://www.sparkasse.de/",
|
||||||
|
"https://www.bahn.de/",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/finanzen/marktberichte/marktbericht-dax-dow-geldanlage-126.html",
|
||||||
|
"https://www.tagesschau.de/inland/innenpolitik/zuckersteuer-134.html",
|
||||||
"https://www.spiegel.de/",
|
"https://www.spiegel.de/",
|
||||||
"https://www.tagesschau.de/",
|
"https://www.tagesschau.de/inland/gesellschaft/15min-podcast-zuckerabgabe-pedo-hunter-erdbeeren-100.html",
|
||||||
"https://de.wikipedia.org/wiki/Spezial:Zuf%C3%A4llige_Seite",
|
"https://www.tagesschau.de/inland/gesellschaft/geburten-rueckgang-100.html",
|
||||||
"https://www.ebay.de/",
|
"https://www.ebay.de/",
|
||||||
"https://www.bild.de/",
|
"https://www.amazon.de/",
|
||||||
"https://www.kicker.de/"
|
"https://www.tagesschau.de/inland/innenpolitik/bundeshaushalt-klingbeil-neuverschuldung-100.html",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/verbraucher/e-autos-deutschland-haeufig-100.html",
|
||||||
|
"https://www.tagesschau.de/wirtschaft/unternehmen/aldi-sued-stellenabbau-sortiment-100.html",
|
||||||
|
"https://www.tagesschau.de/investigativ/report-mainz/iran-volksbank-100.html",
|
||||||
|
"https://www.tum.de/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.bundesregierung.de/",
|
||||||
|
"https://www.arbeitsagentur.de/",
|
||||||
|
"https://www.tum.de/",
|
||||||
|
"https://www.sparkasse.de/",
|
||||||
|
"https://www.bahn.de/",
|
||||||
|
"https://www.amazon.de/",
|
||||||
|
"https://www.ebay.de/",
|
||||||
|
"https://www.spiegel.de/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,37 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://es.wikipedia.org/wiki/Especial:Aleatoria",
|
"https://elpais.com/elviajero/viajes-paco-nadal/2026-04-27/los-atractivos-de-finistere-el-final-de-la-tierra-a-la-francesa.html",
|
||||||
"https://www.elmundo.es/",
|
"https://elpais.com/cultura/2026-04-29/como-edwyn-collins-sobrevivio-a-dos-derrames-cerebrales-volvio-a-la-musica-y-ahora-se-retira-con-honores.html",
|
||||||
"https://www.elpais.com/",
|
"https://www.zara.com/es/",
|
||||||
"https://www.marca.com/",
|
"https://www.elcorteingles.es/",
|
||||||
"https://www.rtve.es/",
|
"https://elpais.com/deportes/futbol/2026-04-28/psg-y-bayern-ponen-el-centro-del-futbol-mundial-en-paris.html",
|
||||||
|
"https://elpais.com/gente/2026-04-28/shakira-recuerda-su-episodio-mas-dificil-en-una-carta-una-manana-me-desperte-siendo-una-mujer-diferente-con-otra-vida.html",
|
||||||
|
"https://administracion.gob.es/",
|
||||||
|
"https://elpais.com/smoda/placeres/2026-04-23/las-creadoras-de-yo-siempre-a-veces-la-serie-sobre-ser-madre-soltera-la-precariedad-lo-esta-marcando-todo-la-gente-se-ve-desbordada.html",
|
||||||
|
"https://elpais.com/clima-y-medio-ambiente/2026-04-28/la-ue-acuerda-normas-comunes-para-proteger-a-perros-y-gatos-de-abusos-y-practicas-comerciales-crueles.html",
|
||||||
|
"https://elpais.com/tecnologia/tu-tecnologia/2026-04-24/merece-la-pena-pagar-por-almacenamiento-extra-en-la-nube-para-tu-movil.html",
|
||||||
|
"https://www.amazon.es/",
|
||||||
|
"https://www.santander.es/",
|
||||||
|
"https://elpais.com/economia/2026-04-29/el-bce-pide-a-la-banca-planes-de-contingencia-ante-el-nuevo-modelo-de-ia-de-anthropic.html",
|
||||||
|
"https://elpais.com/icon/2026-04-29/salir-con-hombres-que-no-van-a-terapia-me-parece-peligroso-la-brecha-de-genero-que-hace-que-ellas-cuiden-mas-de-su-salud-mental.html",
|
||||||
|
"https://www.renfe.com/",
|
||||||
|
"https://elpais.com/deportes/tenis/2026-04-28/baptiste-despide-de-madrid-a-la-campeona-sabalenka.html",
|
||||||
|
"https://elpais.com/escaparate/tecnologia/2026-04-29/robots-limpiapiscinas.html",
|
||||||
|
"https://elpais.com/sociedad/2026-04-28/la-eurocamara-urge-a-la-comision-que-proponga-tipificar-la-violacion-con-el-consentimiento-como-eje-en-toda-la-ue.html",
|
||||||
|
"https://elpais.com/cultura/2026-04-28/un-viaje-de-seis-anos-y-40-idiomas-el-fenomeno-irene-vallejo-encuentra-su-colofon-global-en-el-mundo-arabe.html",
|
||||||
|
"https://www.agenciatributaria.es/",
|
||||||
|
"https://elpais.com/cultura/2026-04-29/el-colapso-anunciado-del-convento-de-cuenca-de-campos-que-expolio-el-magnate-william-randolph-hearst-el-problema-central-es-la-espana-vacia.html",
|
||||||
|
"https://elpais.com/opinion/2026-04-29/yo-a-tu-edad.html"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://administracion.gob.es/",
|
||||||
|
"https://www.agenciatributaria.es/",
|
||||||
|
"https://www.santander.es/",
|
||||||
|
"https://www.renfe.com/",
|
||||||
|
"https://www.amazon.es/",
|
||||||
"https://www.zara.com/es/",
|
"https://www.zara.com/es/",
|
||||||
"https://www.elcorteingles.es/"
|
"https://www.elcorteingles.es/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,37 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://www.lemonde.fr/",
|
"https://www.credit-agricole.fr/",
|
||||||
"https://www.lefigaro.fr/",
|
"https://www.france24.com/fr/%C3%A9missions/info-ou-intox/20260428-tirs-au-gala-de-la-presse-cole-allen-encart%C3%A9-au-parti-d%C3%A9mocrate-et-proche-des-stars",
|
||||||
"https://www.amazon.fr/",
|
"https://www.france24.com/fr/afrique/20260428-senegal-une-reforme-du-code-electoral-ouvre-la-voie-%C3%A0-ousmane-sonko-pour-la-pr%C3%A9sidentielle-de-2029",
|
||||||
"https://www.service-public.fr/",
|
"https://www.sncf.com/",
|
||||||
"https://fr.wikipedia.org/wiki/Sp%C3%A9cial:Page_au_hasard",
|
"https://www.france24.com/fr/europe/20260428-le-futur-premier-ministre-hongrois-peter-magyar-propose-une-rencontre-a-volodymyr-zelensky-ukraine",
|
||||||
|
"https://www.france24.com/fr/vid%C3%A9o/20260428-mali-premi%C3%A8re-apparition-d-assimi-go%C3%AFta-apr%C3%A8s-les-attaques",
|
||||||
|
"https://www.france24.com/fr/am%C3%A9riques/20260428-nouvelle-inculpation-pour-l-ex-directeur-du-fbi-james-comey-b%C3%AAte-noire-de-donald-trump",
|
||||||
|
"https://www.france24.com/fr/vid%C3%A9o/20260428-d%C3%A9troit-d-ormuz-les-n%C3%A9gociations-dans-l-impasse",
|
||||||
|
"https://www.france24.com/fr/europe/20260429-vagues-de-chaleur-fonte-des-glaces-europe-cumule-situations-climatiques-extremes-rapport-copernicus",
|
||||||
|
"https://www.france24.com/fr/moyen-orient/20260429-moyen-orient-en-direct-donald-trump-etats-unis-ont-vaincu-militairement-iran-liban-pete-hegseth-israel",
|
||||||
"https://www.cdiscount.com/",
|
"https://www.cdiscount.com/",
|
||||||
"https://www.fnac.com/"
|
"https://www.france24.com/fr/vid%C3%A9o/20260428-intelligence-artificielle-taylor-swift-veut-faire-de-sa-voix-une-marque-d%C3%A9pos%C3%A9e",
|
||||||
|
"https://www.sorbonne-universite.fr/",
|
||||||
|
"https://www.impots.gouv.fr/",
|
||||||
|
"https://www.france24.com/fr/vid%C3%A9o/20260428-mali-assimi-go%C3%AFta-a-re%C3%A7u-l-ambassadeur-de-russie-selon-la-pr%C3%A9sidence-qui-publie-des-photos",
|
||||||
|
"https://www.france24.com/fr/%C3%A9missions/le-d%C3%A9bat/20260428-mali-le-pouvoir-peut-il-basculer",
|
||||||
|
"https://www.france24.com/fr/vid%C3%A9o/20260428-attaques-au-mali-qui-est-iyad-ag-ghali-%C3%A0-la-t%C3%AAte-du-jnim",
|
||||||
|
"https://www.amazon.fr/",
|
||||||
|
"https://www.france24.com/fr/sports/20260428-mondial-2026-fifa-joueurs-couvrant-bouche-pendant-altercation-recevront-carton-rouge-racisme",
|
||||||
|
"https://www.france24.com/fr/%C3%A9missions/dans-la-presse/20260429-visit-rwanda-sous-les-crampons-la-guerre",
|
||||||
|
"https://www.service-public.fr/",
|
||||||
|
"https://www.france24.com/fr/am%C3%A9riques/20260428-ambassadrice-ukraine-n-a-pas-vol%C3%A9-de-bouteilles-d-alcool-lors-de-la-tentative-d-attentat-contre-trump"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.service-public.fr/",
|
||||||
|
"https://www.impots.gouv.fr/",
|
||||||
|
"https://www.sorbonne-universite.fr/",
|
||||||
|
"https://www.credit-agricole.fr/",
|
||||||
|
"https://www.sncf.com/",
|
||||||
|
"https://www.amazon.fr/",
|
||||||
|
"https://www.cdiscount.com/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,37 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
|
"https://hk.news.yahoo.com/%E5%8F%B2%E4%B8%8A%E9%A0%AD-%E9%81%AD-%E5%90%84%E5%9C%8B%E5%95%9F%E5%8B%95%E5%8C%96%E7%9F%B3%E7%87%83%E6%96%99%E6%B7%98%E6%B1%B0%E8%AB%87%E5%88%A4-070503576.html",
|
||||||
|
"https://www.hku.hk/",
|
||||||
|
"https://hk.news.yahoo.com/%E4%BB%A5%E9%91%91%E8%AD%89%E7%A7%91%E5%AD%B8%E6%BF%80%E7%99%BC%E5%A5%BD%E5%A5%87%E5%BF%83-%E5%B0%8F%E5%AD%B8%E6%A0%A1%E9%95%B7-%E7%A7%91%E5%AD%B8%E4%B8%8D%E6%87%89%E5%8F%AA%E6%98%AF%E5%85%AC%E5%BC%8F%E5%AE%9A%E5%BE%8B%E5%A0%86%E7%96%8A-200000584.html",
|
||||||
|
"https://hk.news.yahoo.com/%E5%B0%96%E6%B2%99%E5%92%80%E9%85%92%E5%BA%97%E8%81%9A%E6%9C%83%E8%AE%8A%E8%A1%9D%E7%AA%81-%E5%85%A7%E5%9C%B0%E5%A5%B3%E5%A4%A7%E9%A6%AC%E7%94%B7%E4%BA%92%E6%AF%86-%E5%90%8C%E9%81%AD%E6%8B%98%E6%8D%95%E9%80%81%E9%99%A2-034529792.html",
|
||||||
|
"https://www.police.gov.hk/",
|
||||||
|
"https://hk.news.yahoo.com/%E7%B2%89%E5%B6%BA%E7%B9%9E%E9%81%93%E6%9D%B1%E6%AE%B5%E5%91%A8%E6%97%A5%E9%80%9A%E8%BB%8A-%E8%81%AF%E5%92%8C%E5%A2%9F%E5%87%BA%E5%B8%82%E5%8D%80%E6%96%99%E5%BF%AB10%E5%88%86%E9%90%98-051625454.html",
|
||||||
|
"https://hk.news.yahoo.com/%E6%99%A8%E6%97%A9%E6%96%B0%E8%81%9E%E9%87%8D%E9%BB%9E-%E7%99%BD%E5%AE%AE%E8%A8%98%E8%80%85%E6%99%9A%E5%AE%B4%E6%A7%8D%E6%93%8A%E6%A1%88%E7%96%91%E7%8A%AF%E8%89%BE%E5%80%AB%E6%8F%90%E5%A0%82-%E8%8B%B1%E7%8E%8B%E6%9F%A5%E7%90%86%E6%96%AF%E4%B8%89%E4%B8%96%E6%8A%B5%E7%BE%8E%E5%B1%95%E9%96%8B%E5%9C%8B%E4%BA%8B%E8%A8%AA%E5%95%8F-232023524.html",
|
||||||
|
"https://hk.news.yahoo.com/%E6%88%B0%E7%88%AD%E8%A1%9D%E6%93%8A-%E6%AD%90%E5%85%83%E5%8D%80%E6%B6%88%E8%B2%BB%E8%80%85%E9%80%9A%E8%86%A8%E9%A0%90%E6%9C%9F%E5%A2%9E%E8%87%B34-140502453.html",
|
||||||
|
"https://hk.news.yahoo.com/%E4%B8%83%E5%9C%B0%E8%81%AF%E6%89%8B%E6%89%93%E6%93%8A%E5%85%92%E7%AB%A5%E8%89%B2%E6%83%85%E7%89%A9%E5%93%81%E7%BD%AA%E8%A1%8C-%E6%8B%98326%E4%BA%BA-9%E6%B8%AF%E4%BA%BA%E8%A2%AB%E6%8D%95-28%E6%AD%B2%E6%BC%A2%E5%8F%A6%E6%B6%89%E5%A4%9A%E6%AC%A1%E9%9D%9E%E7%A6%AE%E7%94%B7%E7%AB%A5-200000224.html",
|
||||||
|
"https://www.hktvmall.com/",
|
||||||
|
"https://www.mtr.com.hk/",
|
||||||
|
"https://hk.news.yahoo.com/%E7%AB%8B%E6%B3%95%E6%9C%83%E4%B8%89%E8%AE%80%E9%80%9A%E9%81%8E2026%E5%B9%B4%E6%92%A5%E6%AC%BE%E6%A2%9D%E4%BE%8B%E8%8D%89%E6%A1%88-050626506.html",
|
||||||
|
"https://hk.news.yahoo.com/google%E9%80%BE600%E5%93%A1%E5%B7%A5%E8%81%AF%E5%90%8D%E4%BF%A1%E8%87%B4ceo-%E7%B1%B2%E6%8B%92%E7%B5%95%E6%A9%9F%E5%AF%86%E8%BB%8D%E4%BA%8Bai%E5%90%88%E7%B4%84-062003403.html",
|
||||||
|
"https://hk.news.yahoo.com/%E5%A0%B1%E5%91%8A-%E5%8C%97%E9%9F%93%E7%96%AB%E6%83%85%E6%9C%9F%E9%96%93%E8%99%95%E6%B1%BA%E4%BA%BA%E6%95%B8%E9%A3%86%E5%8D%87-%E5%A4%9A%E5%9B%A0%E6%94%B6%E7%9C%8B%E5%8D%97%E9%9F%93%E6%88%B2%E5%8A%87%E7%AD%89-143501157.html",
|
||||||
|
"https://hk.news.yahoo.com/%E7%BE%A9%E5%A4%A7%E5%88%A9%E7%B8%BD%E7%90%86-%E7%A9%A9%E5%AE%9A%E7%89%A9%E5%83%B9%E6%98%AF%E9%A6%96%E8%A6%81%E4%BB%BB%E5%8B%99-182002977.html",
|
||||||
|
"https://hk.news.yahoo.com/%E4%BA%9E%E8%82%A1%E6%99%AE%E9%81%8D%E6%94%B6%E9%BB%91-095001022.html",
|
||||||
|
"https://hk.news.yahoo.com/%E8%A8%98%E5%8D%94%E6%99%9A%E5%AE%B4%E9%A9%9A%E6%A7%8D%E6%93%8A-%E7%99%BD%E5%AE%AE%E6%AD%B8%E5%92%8E%E5%B7%A6%E7%BF%BC%E4%BB%87%E6%81%A8%E5%B4%87%E6%8B%9C-230505725.html",
|
||||||
|
"https://hk.news.yahoo.com/%E5%AE%8F%E9%81%93%E9%96%A3%E6%A5%AD%E4%B8%BB%E4%BD%943%E4%B8%8A%E6%A8%93%E5%90%8D%E9%A1%8D-%E7%A7%9F%E5%AE%A2-%E9%BB%9E%E8%A7%A3%E6%94%BF%E5%BA%9C%E5%B9%AB%E5%94%94%E5%88%B0-200000487.html",
|
||||||
|
"https://www.hko.gov.hk/",
|
||||||
|
"https://hk.news.yahoo.com/%E7%99%BD%E5%AE%AE-%E5%B7%9D%E6%99%AE%E8%88%87%E5%9C%8B%E5%AE%89%E9%AB%98%E5%B1%A4%E5%95%86%E8%A8%8E%E4%BC%8A%E6%9C%97%E6%9C%80%E6%96%B0%E6%8F%90%E8%AD%B0-230504137.html",
|
||||||
|
"https://www.hsbc.com.hk/",
|
||||||
|
"https://www.gov.hk/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
"https://www.gov.hk/",
|
"https://www.gov.hk/",
|
||||||
"https://www.hko.gov.hk/",
|
"https://www.hko.gov.hk/",
|
||||||
"https://www.scmp.com/",
|
"https://www.police.gov.hk/",
|
||||||
"https://www.hk01.com/",
|
"https://www.hku.hk/",
|
||||||
"https://zh.wikipedia.org/wiki/Special:Random",
|
"https://www.hsbc.com.hk/",
|
||||||
"https://www.hktvmall.com/",
|
"https://www.mtr.com.hk/",
|
||||||
"https://www.mtr.com.hk/"
|
"https://www.hktvmall.com/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,17 +4,36 @@
|
|||||||
"base_lat": 35.6812,
|
"base_lat": 35.6812,
|
||||||
"base_lon": 139.7671,
|
"base_lon": 139.7671,
|
||||||
"lang_params": "hl=ja&gl=JP",
|
"lang_params": "hl=ja&gl=JP",
|
||||||
"valid_url_suffix": "com"
|
"valid_url_suffix": "com"
|
||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://ja.wikipedia.org/wiki/Special:Random",
|
|
||||||
"https://www.yahoo.co.jp/",
|
|
||||||
"https://www.rakuten.co.jp/",
|
"https://www.rakuten.co.jp/",
|
||||||
"https://www.nhk.or.jp/",
|
"https://news.yahoo.co.jp/pickup/6578089?source=rss",
|
||||||
"kakaku.com/",
|
"https://www.mhlw.go.jp/",
|
||||||
"https://www.goo.ne.jp/",
|
"https://www.japan.go.jp/",
|
||||||
"https://www.amazon.co.jp/"
|
"https://news.yahoo.co.jp/pickup/6578103?source=rss",
|
||||||
|
"https://www.smbc.co.jp/",
|
||||||
|
"https://www.jreast.co.jp/",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578098?source=rss",
|
||||||
|
"https://www.u-tokyo.ac.jp/",
|
||||||
|
"https://www.amazon.co.jp/",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578095?source=rss",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578102?source=rss",
|
||||||
|
"https://www.yahoo.co.jp/",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578100?source=rss",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578096?source=rss",
|
||||||
|
"https://news.yahoo.co.jp/pickup/6578097?source=rss"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.japan.go.jp/",
|
||||||
|
"https://www.mhlw.go.jp/",
|
||||||
|
"https://www.u-tokyo.ac.jp/",
|
||||||
|
"https://www.smbc.co.jp/",
|
||||||
|
"https://www.jreast.co.jp/",
|
||||||
|
"https://www.yahoo.co.jp/",
|
||||||
|
"https://www.amazon.co.jp/",
|
||||||
|
"https://www.rakuten.co.jp/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
36
data/regions/KR/Default/Seoul.json
Normal file
36
data/regions/KR/Default/Seoul.json
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"region_name": "South Korea - Seoul",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 37.5665,
|
||||||
|
"base_lon": 126.978,
|
||||||
|
"lang_params": "hl=ko&gl=KR",
|
||||||
|
"valid_url_suffix": "co.kr"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.daum.net/",
|
||||||
|
"https://www.hometax.go.kr/",
|
||||||
|
"https://www.yonhapnewstv.co.kr/news/AKR202604291353261Wk",
|
||||||
|
"https://www.yonhapnewstv.co.kr/news/MYH20260429124522Cfz",
|
||||||
|
"https://www.coupang.com/",
|
||||||
|
"https://www.yonhapnewstv.co.kr/news/MYH20260429141826Oex",
|
||||||
|
"https://www.snu.ac.kr/",
|
||||||
|
"https://www.korea.kr/",
|
||||||
|
"https://www.kakao.com/",
|
||||||
|
"https://www.yonhapnewstv.co.kr/news/MYH20260429120255UuE",
|
||||||
|
"https://www.kbstar.com/",
|
||||||
|
"https://www.yonhapnewstv.co.kr/news/MYH20260429133604Bz4",
|
||||||
|
"https://www.naver.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.korea.kr/",
|
||||||
|
"https://www.hometax.go.kr/",
|
||||||
|
"https://www.snu.ac.kr/",
|
||||||
|
"https://www.kbstar.com/",
|
||||||
|
"https://www.naver.com/",
|
||||||
|
"https://www.daum.net/",
|
||||||
|
"https://www.coupang.com/",
|
||||||
|
"https://www.kakao.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/MY/Default/Kuala_Lumpur.json
Normal file
50
data/regions/MY/Default/Kuala_Lumpur.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Malaysia - Kuala Lumpur",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 3.139,
|
||||||
|
"base_lon": 101.6869,
|
||||||
|
"lang_params": "hl=en-MY&gl=MY",
|
||||||
|
"valid_url_suffix": "com.my"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.maybank2u.com.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMiwgFBVV95cUxOTmMtWWdXTEJDYUdUZ2twUnNKMXI1SUt3MW9QbEpqSndobHhEMDZ1N3hiU1VyQ1Jta00yREdiaEV1a3N3dTZqQy1ZS0pVNUY0VTRRRllObzcwWlRxM2ZyWFJka212N2ttbEZTZEJBTXd4bjFuaExaX29pVG1YWkhtOG9DZC1BQUx6QmJrY1dCZlRJNTFTcFBDeENlU0dBSDh4Y1NjUG02S0F6Y1ZYWFA2dFlZLVVEOTdfcS1fTXNUc0d6d9IBxwFBVV95cUxQTFZMSlB2cFp3ODB5dk00X3ZJRXNmRW9ZMm0wRkVHeWNob1g4cTF0TG45eVBCdG41NUFuY29EMVBkYUd2MmR0aDhtWE1GMFowdlBEOWY4YVFYZ3NJcHVlbDltZTVkZTI2SUgzbDVDQ3QwLWE5QUEtNDNRb18tSHZvQUs4ZV9mU0VKWWl6Y3Y1aVZreExEd09BTklkTVVONDExcUZwQy1ZN3FaUDFKWWhMLXJjXzg1ODZoeldfZzBsbUtrNXh3OTdj?oc=5",
|
||||||
|
"https://um.edu.my/",
|
||||||
|
"https://www.lazada.com.my/",
|
||||||
|
"https://www.cimbclicks.com.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMi0AFBVV95cUxPdlpkV3RuSklKeG1aVmRLcUdkaWE4akxEOGsySE4tdy1TZjZ3VGtjNV94UDdrR3hOVEFiSVF6MnJXbHpSSkNFZGlwc2t5N21GVXlpRGM5Y2d5VC1UUmJDdkpzakNzSWMtanhfQW9xMnZISUVuVVozSzY5OWQ2aEJoMExVcW9neExaTVA2MTFyZ2xKOXVtS3dqMkZ5ZWRjUHdlMEhkbzFqN0pia01sN2tKMWd1TzcwS0tudkZNMFdreWRvNEJvZ2NyVUlrUFVuQndW?oc=5",
|
||||||
|
"https://www.hasil.gov.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMiywFBVV95cUxQdlVReUVqQ2dKLV9wZUNQcTVlUXU1a0lFeHMzUlVydXdXcDl2VTk4STNNcFBWUXVUUUxtMWl2NUFxSlpaYkh5bjRvbWJidkZpMWY2ekdoR0FMc2NXVURRaWItYjVXM182SzhjWlNyLUZoelhMTHFhVlFiZWRYczdfWWtocnBhX3gxcFpYU0VfeXVkNG5DNzBpNF9QNHczZXVrYjJJR1BFbHRLMS1oUjVEZlFRZDNDVkkxS3MtZHVxNlF4dGJ6RlB4SFFCa9IB0AFBVV95cUxPWHAxTkNoRjRLNE5UcVF1TGRpa3ZzNTczSy11Qmg0WUxqcGhxemV1a3lCOXFQeVlxX1o1dDlpZG04bkpfU0o0N3RMR1pVWDV0RlpRQ2RESnZSOTdlQ0hfdlV0YTFXaW9ENHVncDM1bTV3b0x2aFBzTWtnM0xPeTBtcEFTcXNIMGhwai1tMlVDNGNJSzVtOTJraGpxTFdJZ0JpS2VTN3phOFFKUEZWVlB0X3RTeHRETDJUUTdQOFpZLXhHUEJxMnJHZ3p4c05Oazho?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMie0FVX3lxTE5pdmg2UHVXM3BueUhNbi1lUC15bTRTdkw3Q09wTU9WSlN3TXZqM1cwdVp4b0VTMEZYYlhJUDg0ZWF1RU1waDdtQk9GUURTRmJwMmRybTdLd1Q0UlNaU29ZTmpQd3ZBSXhJUjEtLW02OU03UW5nS0hpOEVhVQ?oc=5",
|
||||||
|
"https://www.pos.com.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMinAFBVV95cUxNckxKeWNrV2ZRQVBNRGd0bWd5Zy1NNWZDZ0FQY3RGVUlNdExVV3NLTFJmWm5pdExJMjB2dmNYVG5YbzRZTEhVZi11bS1odEw4bDhscmZfMURVVWw5LUkxa2JMQU5KZ2JjdHdaTVN6UGxpa0wteUlEeFVWNGM2X09LUnlOclBmMEJ4ejZrSXREcGlISm1KMEZ3bk9uYWQ?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiUEFVX3lxTE0tVFZDUEtnd09DSGh0WGdXbUlGdVpqYmpmMk9Ob2RHWGFoXzRxX3Y2bFlNdWsyNXh1WEwtaWVtdHBsQ2ExS1d5VjZNSFBRdTJL?oc=5",
|
||||||
|
"https://www.kwsp.gov.my/",
|
||||||
|
"https://www.thestar.com.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMi4wFBVV95cUxNSXZxOEFHTXBlR2QxV3hwNjN4YTRwQ19VRTJlaV8tRDVLQzRydkM2eGZlRmJoZW9HUTZPRmZxV1RBM0NpZnFTWHRsNXpBLVRrSmlzVzRDUTdvVXlRT1M0N2tHWXFTRk1aZTF3Q01yZUloWVZ5WU5PbGZaTjNoZ3FRWFNzcDlsMDZpcDhCSnNLdlZKWGxxT0lVWHY2bDNXb1hVS1ZGbFlSdDNwLTBzY1VORnp0MGVyZ0tjeWcwMnlPSFM0WnczT2pHekhNQ1JaS1p6Uk9uQlQzMUdJamRyYUlmRUktVdIB6AFBVV95cUxQZ3QwS180Wi1lak5paDdXMEtBbXR1aDV3bUxOdEJITGc5ZzE4bmlzcXNTdHdHeDljM0Q0VkxDZTl5bS1JaUtwckhEUlVORzZJeHBGRmJFNGJZMlQwYklORVRaR0VibE5CeExyMFhDRHJhZjlBVDJFZkQxcE92WkJub0NYX3IxVi1iX3VzT3ZHeUx1MXpuUy1xNFBYbm90cE9tSWpjejI2cVIwYlBWLTR1bnFsbC1jeDJKMFJuSWZ4aVdVaXFYUlRad1F0V0Vkc1RmdktoSDk0a1l0UHMtbTBzdGhBTlk2WlVz?oc=5",
|
||||||
|
"https://www.malaysia.gov.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMiowFBVV95cUxPNDFQaHRVRmtoRGk1aWk1OXpJYTM1Ml9WTHQwLUhRSmNDRGlEUnNXZlVMYU5Ra2dkNmlXN3dISDNpRnc4Zy1PVklmRHZRUkc0aWVIR25IVEhpcjNxOU5YcXo4UlBuN0E3SlV2MWFERU1CbVJFYTd5cXJNVWwyT3paMy1DRzV0aTZnQUZNenl0U1BQSTVKMHVXeXdjRFBXLXJvX1Iw?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMizwFBVV95cUxQTDhpR0pXNGZKWi0tRG1ORzFMem1zRC1fVWpuMU1ORlVDc3BkQmZsV01udnhTaHotV1JzYmlSQ1dHcFpUNl9idFdRbTBMSXI0bjlLVXJKM0lVUWdBYVpkekw5UjlKRmd6QThMaXJHZ0JXSFBRYVUyVmltcnBzSFgzTlpJZF9mNTdiYTNzVmtPQ25nSnpLUEY3eXR1UVZfRFJwQmRGb1pVZjNodU42NU5TRHNlSXF6Y2ZHbW5tdVBIMEVQOVJXemRuV01PbFQ5czA?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMi1AFBVV95cUxORzJqY2MzQjJVZHlhQ2hDLWxPbWpKVGdoeTIzMzBvMXQ5cTl3WWo4WERnMS13YXRjbkR0UnFCeDVBVkFDOUxsX283UDFBR0VUeVFycUFEM2VzdmQ5RDQ3T1NGa0c1YnZYNkRVZXhpSUxZQ1p1SGJzZnJ1NDF4OUhodW9mWDFZYmJzTGZtUklCTXNEdmVXQmRKV29KZ1JNQS05b1kwY29MTGJVLUg3OHdOcFF3R2wtZDk4a3RwY0dvTVB0SmJ1TkphZ2hLekVNVGFfWFBPOdIB2gFBVV95cUxNQVMzSmJvM1RyMDN5ZjJZUDFsWGNTT0xyOGFwWC14NGY5WE8wT1FIRWNvNm10OXpnS1V0Q0hINW8xa0JMSnZ0Wkc2cUgxdzQ4NjMwMW9reVJHQXJSQmFuaWROeWFsSVVtYkxVUjBNamMxMmFBNHlPQi1LSmZuSm0tXzhnYmtGc1JFUjJ2MVVRYmxONnhKa1Y3NkR0U0VTN1VjR0FsOC1VSFYtQkhNcHZnUU5GZzJpZ2o4RlJMUjF0b2xpeW82aTdIZF9nOUVySEZKYy1CQkpRamo4Zw?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMitAFBVV95cUxPVWtrMmVHOFg4dVktZHN5bTdjUkprY1Y3eVluam1IOWFlMFdaM202NGJvT0lRUnI0V3lSOHE0a3o0YWJfMk16aTItWGY3YWh4OHYzTVQzdS1sYXNQT2trX08zRjhlb1ktRzRIYklSaGdvY3dFZGxhY3hDZ3lfRDJhVm5CNFFhX2lQblF2S1VNNmRKWGk2RGR3bUpaeGFlYWF6RC1rN19LbVc5Z0Jtb0RYbUpyVUjSAboBQVVfeXFMTVVoZlphNERoX2VSWGtBQVdFVTFGblBpWUhUSmxWdExIOVJoVm85YXZjaFc4cVdCaTNEY2NUT3ktV0tzNU5DODdQR2RBLWRvZWRMV0xoUENFaHhka3BUVzNmbnlIaUNqcEx6Zmo5enY2dS1FMU1DYlFwTmlOMFNzbzZVU0JhVFRoazB2S3l2Y01qbk5tbWE2amxfNmk0N1djRUM5a2YyZllmVGs4cnRMWGNvckhYeEUyTnhR?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMimwFBVV95cUxNZDhBR1ZmaGEzSDlNLXdCWEdweVVRTkpNS0tIVUVDWTZHYl9abVlXU0JaeXBCZXlocWRGTUJhb3ZnNTZzZ05CdXJyc1VIZzRvTk40SFJ3U3g0Z0d1VFpCZFlvclo0QzNXaXZnUFhiQzNxdUxiR0xtYjRQTVU0MW0tS0xHMm5sbWJMYTYtb1Y1OEFLaEx0NW1aa1ZQYw?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiyAFBVV95cUxNSmZsZW91OE5iVmc5SnJ3WUtKdG9vQUJCRzB4dzg3clhON0FxeV9ILXZyaXFZVTZDcXFvR2F3Ynkyd0ZXbmkxTnctWDZGdkRWb3ZxaXd2N3pQY3hPNXBXTzdVSmJPMWkzX0ZSR2Z1WldkRWJUYVdwZ2pWRk1mRXl5RzI4aVExdXA4VlUxZEZrNXFwNnkteHUxa1hfR2JIT2NoU21vSTdoUmlid3ZreFBIVDQwbDNSZENUazFpYzdwUE9oTDJaY3hUdA?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMi2gFBVV95cUxOZHp1UzNJNThraERQeEg3ZTRIX19sMDRhS2gxZmhMQUZmN0JIX1FQUlZ4RlZkNGFFTmJvOVBHQXZXVndmNDNFUzlNdG1ZY2VQYWxxRTlLbTdHcUNJb2w2OExFWm44emIzNURWQTlXSjZ1WEpJald5RGNTQWxOS0U4MnZ5cW9HbVdhdmRLLV9DNWRsYTBtVUk2d3NBb2h5UVNWbWlYVnJra2pIdmNCZ3hWMW9mSFJxTkNQeTBXUDkwX0JLNnZjMUVNSXd4RmdINW5Ba2ZUS0lON1VHUQ?oc=5",
|
||||||
|
"https://shopee.com.my/",
|
||||||
|
"https://news.google.com/rss/articles/CBMisgFBVV95cUxQenlTMUZOanBIeGZTNGp3bWJQd0p1X3dVUUdMaGVJMl9OVGhKZHZxQlhkNXkxVlNlLWlLWS05cU1FMmNTLUFicFlRWTNqUlBTVXNfLTYzSENXMDYxdkNKRnlSclFjSnJjM2xIYlBJTzVSSW5ibXh2bFJnNE05LU1uYTBVVjdRdXVnNGdrbjZDY1JPZC05OV9xTWliLVhLV3czZU5NbEdwai0wTm8zbk1ieXFR?oc=5"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.malaysia.gov.my/",
|
||||||
|
"https://www.hasil.gov.my/",
|
||||||
|
"https://www.kwsp.gov.my/",
|
||||||
|
"https://um.edu.my/",
|
||||||
|
"https://www.maybank2u.com.my/",
|
||||||
|
"https://www.cimbclicks.com.my/",
|
||||||
|
"https://www.thestar.com.my/",
|
||||||
|
"https://shopee.com.my/",
|
||||||
|
"https://www.lazada.com.my/",
|
||||||
|
"https://www.pos.com.my/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/NG/Default/Lagos.json
Normal file
50
data/regions/NG/Default/Lagos.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Nigeria - Lagos",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 6.5244,
|
||||||
|
"base_lon": 3.3792,
|
||||||
|
"lang_params": "hl=en-NG&gl=NG",
|
||||||
|
"valid_url_suffix": "com.ng"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://punchng.com/wbank-commits-8-2bn-to-africas-power-supply/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.nairaland.com/",
|
||||||
|
"https://www.konga.com/",
|
||||||
|
"https://punchng.com/33-ambassadors-secure-agrement-32-pending-fg/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.airtel.com.ng/",
|
||||||
|
"https://www.firstbanknigeria.com/",
|
||||||
|
"https://punchng.com/six-arrested-after-attack-on-kano-phone-market/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/three-jailed-97-years-for-abduction-in-ekiti/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/oau-announces-three-week-break-after-students-transport-protest-2/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/firms-return-to-profit-despite-policy-shifts-report/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/wafcon-postponement-frustrating-nnadozie/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.jumia.com.ng/",
|
||||||
|
"https://www.mtn.ng/",
|
||||||
|
"https://punchng.com/naseni-empowers-2000-kano-households/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/naca-unveils-technical-team-for-aids-control-in-anambra/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://guardian.ng/",
|
||||||
|
"https://punchng.com/fashola-honours-insurance-exco-at-book-launch/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/efcc-chair-urges-ai-adoption-in-corruption-fight/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.punchng.com/",
|
||||||
|
"https://punchng.com/east-africa-attracts-4-1bn-investment-amid-reforms/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.gtbank.com/",
|
||||||
|
"https://punchng.com/n1m-wage-useless-if-naira-remains-weak-ajaero/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://www.vanguardngr.com/",
|
||||||
|
"https://punchng.com/osimhen-to-arsenal-odumodu-vows-to-buy-emirates-season-ticket/?utm_source=rss.punchng.com&utm_medium=web",
|
||||||
|
"https://punchng.com/im-yet-to-get-flying-eagles-job-maikaba/?utm_source=rss.punchng.com&utm_medium=web"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.jumia.com.ng/",
|
||||||
|
"https://www.punchng.com/",
|
||||||
|
"https://www.gtbank.com/",
|
||||||
|
"https://guardian.ng/",
|
||||||
|
"https://www.konga.com/",
|
||||||
|
"https://www.firstbanknigeria.com/",
|
||||||
|
"https://www.vanguardngr.com/",
|
||||||
|
"https://www.nairaland.com/",
|
||||||
|
"https://www.airtel.com.ng/",
|
||||||
|
"https://www.mtn.ng/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,13 +8,37 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://nl.wikipedia.org/wiki/Speciaal:Willekeurig",
|
"https://nos.nl/l/2612356",
|
||||||
"https://www.rijksoverheid.nl/",
|
"https://nos.nl/l/2612359",
|
||||||
"https://www.nos.nl/",
|
"https://www.belastingdienst.nl/",
|
||||||
"https://www.bol.com/",
|
"https://nos.nl/l/2612325",
|
||||||
"https://www.nu.nl/",
|
|
||||||
"https://www.buienradar.nl/",
|
"https://www.buienradar.nl/",
|
||||||
"https://www.telegraaf.nl/"
|
"https://nos.nl/l/2612330",
|
||||||
|
"https://www.rijksoverheid.nl/",
|
||||||
|
"https://nos.nl/l/2612347",
|
||||||
|
"https://nos.nl/l/2612317",
|
||||||
|
"https://nos.nl/l/2612357",
|
||||||
|
"https://www.ing.nl/",
|
||||||
|
"https://nos.nl/l/2612346",
|
||||||
|
"https://nos.nl/l/2612324",
|
||||||
|
"https://www.ns.nl/",
|
||||||
|
"https://nos.nl/l/2612335",
|
||||||
|
"https://nos.nl/l/2612358",
|
||||||
|
"https://nos.nl/l/2612343",
|
||||||
|
"https://nos.nl/l/2612332",
|
||||||
|
"https://nos.nl/l/2612354",
|
||||||
|
"https://nos.nl/l/2612338",
|
||||||
|
"https://www.bol.com/",
|
||||||
|
"https://www.marktplaats.nl/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.rijksoverheid.nl/",
|
||||||
|
"https://www.belastingdienst.nl/",
|
||||||
|
"https://www.ing.nl/",
|
||||||
|
"https://www.ns.nl/",
|
||||||
|
"https://www.bol.com/",
|
||||||
|
"https://www.marktplaats.nl/",
|
||||||
|
"https://www.buienradar.nl/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,39 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://www.straitstimes.com/",
|
"https://www.channelnewsasia.com/business/it-group-sopra-steria-posts-32-organic-rise-in-first-quarter-revenue-6088326",
|
||||||
"https://www.channelnewsasia.com/",
|
"https://www.iras.gov.sg/",
|
||||||
|
"https://www.channelnewsasia.com/sustainability/tropical-forest-loss-eases-in-2025-record-high-report-shows-6088141",
|
||||||
|
"https://www.channelnewsasia.com/singapore/baggage-handling-luggage-toss-changi-airport-sats-apologises-video-6088016",
|
||||||
|
"https://www.channelnewsasia.com/singapore/paynow-nickname-feature-removed-banks-abs-jun-6-6088091",
|
||||||
|
"https://www.channelnewsasia.com/business/white-house-drafts-guidance-bypass-anthropics-risk-flag-new-ai-models-axios-reports-6088041",
|
||||||
|
"https://www.channelnewsasia.com/singapore/police-close-sph-media-inflated-circulation-numbers-probe-investigation-no-further-action-6088211",
|
||||||
|
"https://www.channelnewsasia.com/east-asia/new-zealand-officials-reject-statue-remembering-japans-sex-slaves-6088281",
|
||||||
|
"https://www.channelnewsasia.com/world/oil-prices-rise-us-extend-iran-ports-blockade-6087926",
|
||||||
|
"https://www.dbs.com.sg/",
|
||||||
|
"https://www.cpf.gov.sg/",
|
||||||
|
"https://www.nus.edu.sg/",
|
||||||
|
"https://www.channelnewsasia.com/east-asia/robots-baggage-handling-japan-tokyo-haneda-airport-6087891",
|
||||||
|
"https://www.channelnewsasia.com/business/south-korea-exports-seen-rising-sharply-again-in-april-chip-boom-reuters-poll-6088296",
|
||||||
|
"https://www.channelnewsasia.com/entertainment/charlene-choi-wedding-elvis-lam-6087961",
|
||||||
|
"https://www.channelnewsasia.com/entertainment/hong-kong-louis-koo-jessica-hsuan-first-duet-kiss-in-music-video-6088186",
|
||||||
"https://www.gov.sg/",
|
"https://www.gov.sg/",
|
||||||
"https://shopee.sg/",
|
"https://www.channelnewsasia.com/east-asia/us-allies-release-joint-statement-supporting-panamas-sovereignty-6087651",
|
||||||
"https://en.wikipedia.org/wiki/Special:Random",
|
"https://www.singpass.gov.sg/",
|
||||||
|
"https://www.channelnewsasia.com/entertainment/singaporeans-amazon-prime-video-beast-games-6087921",
|
||||||
"https://www.fairprice.com.sg/",
|
"https://www.fairprice.com.sg/",
|
||||||
"https://www.dbs.com.sg/"
|
"https://www.shopee.sg/",
|
||||||
|
"https://www.channelnewsasia.com/brand-studio/tackling-breast-cancer-gap-in-southeast-asia-6078596"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.gov.sg/",
|
||||||
|
"https://www.cpf.gov.sg/",
|
||||||
|
"https://www.iras.gov.sg/",
|
||||||
|
"https://www.singpass.gov.sg/",
|
||||||
|
"https://www.nus.edu.sg/",
|
||||||
|
"https://www.dbs.com.sg/",
|
||||||
|
"https://www.shopee.sg/",
|
||||||
|
"https://www.fairprice.com.sg/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
48
data/regions/TW/Default/Taipei.json
Normal file
48
data/regions/TW/Default/Taipei.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"region_name": "Taiwan - Taipei",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 25.033,
|
||||||
|
"base_lon": 121.5654,
|
||||||
|
"lang_params": "hl=zh-TW&gl=TW",
|
||||||
|
"valid_url_suffix": "com.tw"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://news.google.com/rss/articles/CBMiZ0FVX3lxTFBJQ1pKeHNvaGVpcTlTVnRnejJfZE81YW5EUnltV1Y2TktiQ1Nta3dHMmVkQkNaVnV4b2ZRVFhIV3c5U1R4RWNENXBzbzZxbjhKdVowWHV5QWNjdFRndk9zaGhncFVsRTQ?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiU0FVX3lxTE1LSzVpMTZjLTJrMzVBNDd5UHlGLU0wMU1RYW56SU13cXdtc0RELUNUM2pHb3FScWN4VGhlZ3NmeDI1Szl4Y3RYalU3Y1l5WUJwRFk40gFYQVVfeXFMT1BzM2ZDeHltMnNvUzFvdk5INzJwRTI1X2pReVhSa2w2dHVDZUhuVm13Q2FKOGFjQllpT1Y2dFF0VEJJSzl2eXlBV1E5WVBpUVFCa3MzYk51Rg?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiXkFVX3lxTE03elBISEhWSzBQcFNhcUZCMlItUVg5T0JOU0hhZlNTUkZBOUo3SjdWOWEwUnlobngzc0VYMXp6UnJRdC0zazZjOVQwMHE0ck9mazFsTW9pQ0RsaFA4OUHSAWhBVV95cUxPdnlKUEEydWliQ3pXbDVQcUtMNTU2dHlXYUcyaWRkTVVjbnYybVV5Q1BCTzRDRjgwektQUVhZU0lFWEw0U1Z5RENsTUljRHVnanFLbUtNM0VaeEs2U1dYdTROR3pPWjlPMw?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiVkFVX3lxTE12cTFwWVBCbmRQUFJwNFFnaTkzOEV0dDRDVXlYclQ0TUJFRnF6N0gzYkNacEFDTHVRTUM5U0NJYmk3d3JlZlQ4dGs0czVCWFc5WXkyajJn?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiX0FVX3lxTE00RHhRdGxaWEdtYzBNWHA1XzN6TUthYUNOSTZhY1R5Q2dnZ3l2V3ZaQWpGU0VkbGlvTEh3TkVyMWtUMV9HbkJ1dmE1N3pUYU9GRW5JR01CQXlTMjQxTlJr?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiUEFVX3lxTE5kVWhLRWNRc1FmNnRWV1ZDTE1vYmpTTVpBUm9TSmxESkJNc2dwSXJITjVjb25MSG9VanlTNXFvTEF6TVdZNWZmVmZZcXNSQVJo0gFWQVVfeXFMTXBYcmtzRDZWZjNlSkx1Tl8xWUhPUmR5Ul83Y2lhZ0RBZTFyNUdTdE1rV3c4R1ZMNWRXTFBsVnpQa0xYVGN3QWlSanpkWWZOR2gyZUdyU1E?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiUEFVX3lxTE9lV3pNRVdjZTZwanFaTzFkTkYxWGNiVWw3eFk5MllYWFZKWmIySWlqMEN3VzZFUEJCU1A2Ql9vaE1udHkyR1ZkVHFaN19YdzNM0gFWQVVfeXFMTnlUZll0TWdQUEpBa1k4X1hlb3FSd2hmdmN5V0FBSGctb2lDY3NCb0ktanlKQkZ4RmZvR20zbmFwTlhwQXluc1ktazJDT2thTmh4a0pOdWc?oc=5",
|
||||||
|
"https://www.pchome.com.tw/",
|
||||||
|
"https://news.google.com/rss/articles/CBMiZEFVX3lxTFBoTzZJOVh3T2VNa3JuNWNWZGk4YzdTQ19UUm5qREVIYklTYVQzQnV0OHB3b2xpWmVpRTRiZXdIZG9qckM0bTZ2aGhMcGZGVVdUcWQ5LWxvSTVDc290bU5vZk14OUXSAWpBVV95cUxNTk9FNDlsb0RUSkVzTkszRnhWbjVGNG92ajdLRm9BQlF1a3VFY3FSWG4zQ0dUSVJCZzcyS2lyYS1lbWdTNzZwUDNiZHdHTzdIZEpCWGwzRTFRTkNKRi1neVNaSnJ0UTV3VThB?oc=5",
|
||||||
|
"https://www.ntu.edu.tw/",
|
||||||
|
"https://www.gov.tw/",
|
||||||
|
"https://www.momoshop.com.tw/",
|
||||||
|
"https://www.thsrc.com.tw/",
|
||||||
|
"https://news.google.com/rss/articles/CBMi2AJBVV95cUxObjlHcnQwZ3JzWnpLVEEtVjliSTBrTjljZU1oZkNET2Zoc0Q3cFlZN1BxMGVpQUwwSWgtSFF5eDRDWHVuRHVmVjMtUWloZlpiVm1nMjJnbjJpUU55ZU04dC1wZFlmeC04eXVWaHpJU3RtdTRjVkhhaDFPMldDZjl2NDlUR1VLX2dudXpOdTNKVHpkSmpZcGNXdVg0cHFrUlc3b05jUWZVR2h1QWVQOHhrb3FpTFVLNndVU1ZuRDhZTlBCeUxPcWktM3EtQ25vSWt2S1BublZsT05WNTFTS0lrUzdvZUhGREprcW4zXzdoRDlHTzg1cnFVelZ2ZWtOaFZuSEI4dlM2a21ocjhJU3Zwd3FKdTlhZVc3dTh5LUdqNDE1NzhPSjM1SFp1dEZQSzBYRnFuOEZqekJ3QWJCN3JTTENVY25IR1RkbjVTUkw1NjkxNkNfZjkwdg?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiTkFVX3lxTFBKNXFmNWZJbFRBMFpDSEl4b0ZGLWE1bmZ0ZG5qZ0FaZzlDeDY1QTZZRGV0ejd3cUtiUEUxUW1TTTk0eTFRVWJtX2dwQlRuZ9IBakFVX3lxTE1vd1NtY0FRSy16ZVVxdkllb0VzcE9UWVNFQ0VXSnRFcmFfUlk1SmlZUWlLblhwRmdpc3BncVRBTHVoSXRTOWJXZEZYcVVLZWZhMDBMV0dNQjR0TUlVRHpfXzVCb25EblI3aFE?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiX0FVX3lxTE9HQnlhb0h4OEhTMmpxV1VtMXcyMmk5ZVVWZXZwYXh0dGRKWUR6dXMyU3RCcmJEcVFOUzNwMnlIa25jaUJ4Slp1SjQ1UXB1Y3FHWVR6dlRYeWdxUW9zMjJJ0gFkQVVfeXFMTVROck1hbVFzSjIwWndLcXBuYmZ5UXZ6M09UT2IxcUhHdUdUMWhWbWJpcTFjREZXd1dxcGRuTEJ1QkxES0pNYzJXZ01vQWNnSzB5RXVWZnpPS3lnLTJUS0sydG9iaw?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiS0FVX3lxTE9uWm1hTDZTTm9tYkg4WjFudTlxVURTOEFMQ2FxMXZUT2R3ZmFWZVpmTGpyRVRYNndYbnZSMUs1VzQyTUhmQVlYd3BIdw?oc=5",
|
||||||
|
"https://www.cathaybk.com.tw/",
|
||||||
|
"https://www.dcard.tw/",
|
||||||
|
"https://news.google.com/rss/articles/CBMi6gNBVV95cUxPMThyWDl6MWlueF8yUnFYWkF0d0xPYlMyNC1rakFHUE9yUFhOcnc1YUtXUXFxdlNYRU1odzEwc0tQZmFtUEhxbVhHZWRKMHBBXy04WFk5OFJXZUw5dFpVU2tiVWZNeVc3QnpHMWlJaTFKQkNqOWZMV3V0eTVGRHZKV0ZLZl9DekE3cjdvTU1vQVdPN3RGdlJBS0Z4c3Yyb3EyU3dXSVRhWTd0cmFmeEgyUjViOTVrSEhSX29DcHhER1FFbTV0OWM1ZDczR1B5Slp1RzlLS2xqZ3EzQ3E5cUZRemxOTWJkRFR6S1U5STBRbHZNSlU4NHZicDFIbWc2Q2V2RlhzNjkxN19WWFJLcklISDRDcjd2TU94aWV1Z3JLZzcwT2h1THlGNzgwdnEyQkt0X29KMURSZ0VzaUNlSEJvZURtSGRQSmJvei1XUmRSVlRPa3R2RFAzWmZBYXNTdndIYktPbDh4ZVdwUHZfam9scFBKTF94ZkJPaHBSdENkYXQ2RTEteGtvYjN3blZOamE3VDhRZUlqRkVvY0wzV24yems1Nk1DazhFQnlUOEx1UVFCeGViTTM0M3RqU3NONDRQY05MSUxvaE9VSUFyekdBek9rTS0tUDN0WDFJQmxsOTBqWlZVZ2tXUVhB?oc=5",
|
||||||
|
"https://news.google.com/rss/articles/CBMiW0FVX3lxTE9UVEhMMGpES0xXYTdMdFJ1RV82UTRwemVQV0lSUG5oN1hVZTVZZEZWbm9hY3JscjRRS29lT1NrUzBPYzFwdkIzQ0Uzd2dYQmd4WE4wZ0VOTUdETEk?oc=5",
|
||||||
|
"https://tw.yahoo.com/",
|
||||||
|
"https://news.google.com/rss/articles/CBMigAJBVV95cUxQRWo0XzR4MkRyemV4NFhjcGJIRm5EamRPeklqeXR0NFJBQ09CWHVKLWtzRFJ2X3l0VFFwTjlxTFloSHVBRTMxS0ViM29fbHl2dXljaHRfdlBwVHlBQ29EcEZ6TkthOG9GclJjblY0YnJmWTh6TzZSUnNrclJPbXpuNy0yczAzbjJaeHhJMVM3ZEdReWN3TURzb2VtSklDZDg2QUhhSVE0VnZGd1RuclRWOW9LZUR0aXpNdjJ1clBGQnhlZ1psOU44eVprVXB6bTBFYjdncHEwQXpfbHd6dFlVZmNVYlp0S0hSbFN2aGFYQ0FCMFdVYTBRWFlibzlNUmJu?oc=5",
|
||||||
|
"https://www.post.gov.tw/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.gov.tw/",
|
||||||
|
"https://www.post.gov.tw/",
|
||||||
|
"https://www.ntu.edu.tw/",
|
||||||
|
"https://www.cathaybk.com.tw/",
|
||||||
|
"https://www.thsrc.com.tw/",
|
||||||
|
"https://tw.yahoo.com/",
|
||||||
|
"https://www.momoshop.com.tw/",
|
||||||
|
"https://www.pchome.com.tw/",
|
||||||
|
"https://www.dcard.tw/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
46
data/regions/UK/Default/Coventry.json
Normal file
46
data/regions/UK/Default/Coventry.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United Kingdom - Coventry",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 52.4068,
|
||||||
|
"base_lon": -1.5197,
|
||||||
|
"lang_params": "hl=en&gl=GB",
|
||||||
|
"valid_url_suffix": "co.uk"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.bbc.com/news/articles/c62r8lzgnk2o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.co.uk/news/10628994?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/c4g0zwxl3k0o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/cj4pxyklw1jo?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/sport/football/articles/c202rgdlqxqo?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.postoffice.co.uk/",
|
||||||
|
"https://www.bbc.com/sport/golf/articles/c78q5v8y939o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/c8jvl3x19v9o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/ce8p020r1y8o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.nhs.uk/",
|
||||||
|
"https://www.ox.ac.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/cp3p5l0nyevo?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.barclays.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/cze25j9p1k7o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.gov.uk/",
|
||||||
|
"https://www.ebay.co.uk/",
|
||||||
|
"https://www.nationalrail.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c87qglyjr44o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.co.uk/sounds/play/p0ngrsbh?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/ce8j8xxzzjko?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/c78kl05en7po?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.amazon.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c5yx8lj4652o?at_medium=RSS&at_campaign=rss"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.gov.uk/",
|
||||||
|
"https://www.nhs.uk/",
|
||||||
|
"https://www.ox.ac.uk/",
|
||||||
|
"https://www.barclays.co.uk/",
|
||||||
|
"https://www.postoffice.co.uk/",
|
||||||
|
"https://www.nationalrail.co.uk/",
|
||||||
|
"https://www.amazon.co.uk/",
|
||||||
|
"https://www.ebay.co.uk/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,13 +8,39 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://www.bbc.co.uk/",
|
"https://www.bbc.com/news/articles/ce8j8xxzzjko?at_medium=RSS&at_campaign=rss",
|
||||||
"https://www.gov.uk/",
|
"https://www.bbc.com/sport/football/articles/c202rgdlqxqo?at_medium=RSS&at_campaign=rss",
|
||||||
"https://www.amazon.co.uk/",
|
"https://www.bbc.com/news/articles/cj4pxyklw1jo?at_medium=RSS&at_campaign=rss",
|
||||||
"https://www.theguardian.com/uk",
|
"https://www.bbc.co.uk/sounds/play/p0ngrsbh?at_medium=RSS&at_campaign=rss",
|
||||||
"https://www.nhs.uk/",
|
"https://www.nhs.uk/",
|
||||||
"https://en.wikipedia.org/wiki/Special:Random",
|
"https://www.bbc.com/news/articles/ce8p020r1y8o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/c4g0zwxl3k0o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.nationalrail.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c5yx8lj4652o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.amazon.co.uk/",
|
||||||
|
"https://www.postoffice.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c78kl05en7po?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/c87qglyjr44o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.co.uk/news/10628994?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.gov.uk/",
|
||||||
|
"https://www.barclays.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c8jvl3x19v9o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.ebay.co.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/c62r8lzgnk2o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/sport/golf/articles/c78q5v8y939o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.bbc.com/news/articles/cze25j9p1k7o?at_medium=RSS&at_campaign=rss",
|
||||||
|
"https://www.ox.ac.uk/",
|
||||||
|
"https://www.bbc.com/news/articles/cp3p5l0nyevo?at_medium=RSS&at_campaign=rss"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.gov.uk/",
|
||||||
|
"https://www.nhs.uk/",
|
||||||
|
"https://www.ox.ac.uk/",
|
||||||
|
"https://www.barclays.co.uk/",
|
||||||
|
"https://www.postoffice.co.uk/",
|
||||||
|
"https://www.nationalrail.co.uk/",
|
||||||
|
"https://www.amazon.co.uk/",
|
||||||
"https://www.ebay.co.uk/"
|
"https://www.ebay.co.uk/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,43 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://en.wikipedia.org/wiki/Special:Random",
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
"https://www.yahoo.com/",
|
"https://www.usa.gov/",
|
||||||
"https://www.target.com/",
|
|
||||||
"https://www.npr.org/",
|
|
||||||
"https://www.weather.com/",
|
|
||||||
"https://www.amazon.com/",
|
"https://www.amazon.com/",
|
||||||
"https://www.cdc.gov/"
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.walmart.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,43 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://en.wikipedia.org/wiki/Special:Random",
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
"https://www.yahoo.com/",
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
"https://www.target.com/",
|
"https://www.irs.gov/",
|
||||||
"https://www.npr.org/",
|
"https://www.usps.com/",
|
||||||
"https://www.weather.com/",
|
|
||||||
"https://www.amazon.com/",
|
|
||||||
"https://www.cdc.gov/",
|
"https://www.cdc.gov/",
|
||||||
"https://www.mercurynews.com/"
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
50
data/regions/US/IL/Warrenville.json
Normal file
50
data/regions/US/IL/Warrenville.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Warrenville",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 41.8164,
|
||||||
|
"base_lon": -88.1748,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/NC/Charlotte.json
Normal file
50
data/regions/US/NC/Charlotte.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Charlotte",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 35.2271,
|
||||||
|
"base_lon": -80.8431,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/NV/Las_Vegas.json
Normal file
50
data/regions/US/NV/Las_Vegas.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Las Vegas",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 36.1699,
|
||||||
|
"base_lon": -115.1398,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.amazon.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/OR/Bend.json
Normal file
50
data/regions/US/OR/Bend.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Bend",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 44.0582,
|
||||||
|
"base_lon": -121.3153,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.usa.gov/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/TX/Dallas.json
Normal file
50
data/regions/US/TX/Dallas.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Dallas",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 32.7767,
|
||||||
|
"base_lon": -96.797,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.dallasnews.com/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.nytimes.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.texas.gov/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.foxnews.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.texas.gov/",
|
||||||
|
"https://www.dallasnews.com/",
|
||||||
|
"https://www.cnn.com/",
|
||||||
|
"https://www.foxnews.com/",
|
||||||
|
"https://www.nytimes.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
40
data/regions/US/TX/Houston.json
Normal file
40
data/regions/US/TX/Houston.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"region_name": "USA - Houston",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 29.7604,
|
||||||
|
"base_lon": -95.3698,
|
||||||
|
"lang_params": "hl=en-US&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.nasa.gov/",
|
||||||
|
"https://www.rice.edu/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.mdanderson.org/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.houstonchronicle.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.houstontx.gov/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.houstontx.gov/",
|
||||||
|
"https://www.houstonchronicle.com/",
|
||||||
|
"https://www.rice.edu/",
|
||||||
|
"https://www.mdanderson.org/",
|
||||||
|
"https://www.nasa.gov/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/UT/Salt_Lake_City.json
Normal file
50
data/regions/US/UT/Salt_Lake_City.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Salt Lake City",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 40.7608,
|
||||||
|
"base_lon": -111.891,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.walmart.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
50
data/regions/US/WA/Seattle.json
Normal file
50
data/regions/US/WA/Seattle.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"region_name": "United States - Seattle",
|
||||||
|
"google_module": {
|
||||||
|
"base_lat": 47.6062,
|
||||||
|
"base_lon": -122.3321,
|
||||||
|
"lang_params": "hl=en&gl=US",
|
||||||
|
"valid_url_suffix": "com"
|
||||||
|
},
|
||||||
|
"trust_module": {
|
||||||
|
"white_urls": [
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802343/reflecting-pool-resurfacing-blue-trump",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.cnn.com/2023/04/18/politics/schumer-senate-feinstein-vote-cardin/index.html",
|
||||||
|
"https://www.usps.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.cnn.com/cnn-underscored/money/how-to-file-taxes?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.cnn.com/style/article/marilyn-minter-artist-elder-sex/index.html",
|
||||||
|
"https://www.cnn.com/videos/politics/2023/04/18/jake-tapper-dominion-lawsuit-settlement-fox-news-statement-lead-vpx.cnn",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.cnn.com/travel/article/southwest-airlines-flight-delays/index.html",
|
||||||
|
"https://www.cnn.com/videos/tech/2023/04/18/apple-store-mumbai-india-ceo-tim-cook-vedika-sud-ovn-biz-ldn-vpx.cnn",
|
||||||
|
"https://www.cnn.com/cnn-underscored/reviews/best-bidets?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802968/education-secretary-linda-mcmahon-senate-hearing",
|
||||||
|
"https://www.cnn.com/2023/04/18/entertainment/jake-gyllenhaal-jamie-lee-curtis-pandemic-living/index.html",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.cnn.com/videos/us/2023/04/18/pizza-guy-trips-perp-moos-cprog-orig-bdk.cnn",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.npr.org/2026/04/28/nx-s1-5802997/fcc-abc-license-renewal-melania-trump-jimmy-kimmel",
|
||||||
|
"https://www.cnn.com/2023/04/18/media/fox-dominion-settlement/index.html",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.cnn.com/2023/04/18/tech/lina-khan-ai-warning/index.html",
|
||||||
|
"https://www.cnn.com/cnn-underscored/deals/wayfair-way-day-2023-04-17?iid=CNNUnderscoredHPcontainer",
|
||||||
|
"https://www.chase.com/"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://www.usa.gov/",
|
||||||
|
"https://www.irs.gov/",
|
||||||
|
"https://www.cdc.gov/",
|
||||||
|
"https://www.harvard.edu/",
|
||||||
|
"https://www.chase.com/",
|
||||||
|
"https://www.bankofamerica.com/",
|
||||||
|
"https://www.amazon.com/",
|
||||||
|
"https://www.target.com/",
|
||||||
|
"https://www.walmart.com/",
|
||||||
|
"https://www.usps.com/"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,13 +8,37 @@
|
|||||||
},
|
},
|
||||||
"trust_module": {
|
"trust_module": {
|
||||||
"white_urls": [
|
"white_urls": [
|
||||||
"https://vi.wikipedia.org/wiki/Đặc_biệt:Ngẫu_nhiên",
|
"https://vnexpress.net/csgt-tai-xe-khong-co-loi-khi-huc-vang-nguoi-di-xe-may-5068180.html",
|
||||||
"https://chinhphu.vn/",
|
"https://vnexpress.net/thu-tuong-yeu-cau-khong-de-thieu-dien-tang-mua-tu-lao-va-trung-quoc-5068211.html",
|
||||||
"https://vnexpress.net/",
|
|
||||||
"https://tuoitre.vn/",
|
|
||||||
"https://vtv.vn/",
|
|
||||||
"https://shopee.vn/",
|
"https://shopee.vn/",
|
||||||
"https://tiki.vn/"
|
"https://vnexpress.net/gia-mot-oto-o-my-mua-duoc-4-xe-dien-trung-quoc-5068089.html",
|
||||||
|
"https://tiki.vn/",
|
||||||
|
"https://vnexpress.net/san-bay-thanh-son-duoc-de-xuat-phuc-vu-ca-dan-su-va-quoc-phong-5068098.html",
|
||||||
|
"https://vnexpress.net/psg-nhan-hai-diem-9-truoc-bayern-5068087.html",
|
||||||
|
"https://vnu.edu.vn/",
|
||||||
|
"https://vnexpress.net/tuong-dau-xuong-khop-hoa-suy-gian-tinh-mach-5068267.html",
|
||||||
|
"https://chinhphu.vn/",
|
||||||
|
"https://vnexpress.net/tp-hcm-khoi-cong-trung-tam-hanh-chinh-30-000-ty-dong-va-cai-tao-ben-nha-rong-5068191.html",
|
||||||
|
"https://vnexpress.net/lpbank-thanh-lap-ngan-hang-con-tai-trung-tam-tai-chinh-vifc-5068261.html",
|
||||||
|
"https://dichvucong.gov.vn/",
|
||||||
|
"https://vnexpress.net/wuling-macaron-xe-dien-ti-hon-gia-tu-269-trieu-dong-5068141.html",
|
||||||
|
"https://vnexpress.net/do-vui-trac-nghiem-chinh-ta-tieng-viet-tu-nao-viet-dung-chinh-ta-sup-hay-xup-5068126.html",
|
||||||
|
"https://vnexpress.net/giai-phap-quang-cao-facebook-khau-tru-10-vat-tu-aka-media-5066627.html",
|
||||||
|
"https://vnexpress.net/the-kho-voi-tong-thong-mexico-trong-cuoc-chien-chong-ma-tuy-cua-my-5067950.html",
|
||||||
|
"https://vnexpress.net/",
|
||||||
|
"https://vnexpress.net/chao-em-nguoi-co-the-khien-ngay-binh-thuong-tro-nen-y-nghia-5068245.html",
|
||||||
|
"https://vnexpress.net/kinh-te-lien-vung-tao-trien-vong-cho-bat-dong-san-phan-thiet-5068189.html",
|
||||||
|
"https://www.vietcombank.com.vn/",
|
||||||
|
"https://vnexpress.net/dien-bien-kho-luong-sau-tuan-hai-vong-bang-giai-bong-ro-tre-vnexpress-5068182.html"
|
||||||
|
],
|
||||||
|
"static_urls": [
|
||||||
|
"https://chinhphu.vn/",
|
||||||
|
"https://dichvucong.gov.vn/",
|
||||||
|
"https://vnu.edu.vn/",
|
||||||
|
"https://www.vietcombank.com.vn/",
|
||||||
|
"https://shopee.vn/",
|
||||||
|
"https://tiki.vn/",
|
||||||
|
"https://vnexpress.net/"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,15 +5,31 @@
|
|||||||
# 核心功能: 部署/卸载调度中枢、SQLite 资产管理、平滑热更新引擎
|
# 核心功能: 部署/卸载调度中枢、SQLite 资产管理、平滑热更新引擎
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 🛑 核心权限防线: 检查是否以 root 权限运行
|
||||||
|
# ==========================================================
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "\033[31m❌ 权限被拒绝: 部署 IP-Sentinel 需要最高系统权限。\033[0m"
|
||||||
|
echo -e "💡 请切换到 root 用户 (执行 su root 或 sudo -i) 后重新运行指令。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 🟢 [防劫持沙盒] 引入司令部专属随机安全工作区
|
||||||
|
SECURE_TMP=$(mktemp -d /tmp/ips_master_install.XXXXXX)
|
||||||
|
trap 'rm -rf "$SECURE_TMP"' EXIT HUP INT QUIT TERM
|
||||||
|
|
||||||
# 你的 GitHub 仓库 Raw 数据直链前缀
|
# 你的 GitHub 仓库 Raw 数据直链前缀
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
# 临时改为私库地址用于测试
|
# 临时改为开发地址用于测试
|
||||||
# REPO_RAW_URL="https://git.94211762.xyz/hotyue/IP-Sentinel/raw/branch/main"
|
# REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/v3.6.2-rc"
|
||||||
|
|
||||||
# [核心: 动态获取全局版本控制锚点 (Single Source of Truth)]
|
# [核心: 动态提取 Master 专属版本锚点 (KV 解析法)]
|
||||||
TARGET_VERSION=$(curl -s -m 3 "${REPO_RAW_URL}/version.txt" | tr -d '[:space:]')
|
# 通过 grep 定位 MASTER_VERSION 行,再通过 cut 提取等号右侧的值
|
||||||
# 🛡️ 兜底防线:如果网络波动拉取失败,启用内置的安全兜底版本
|
# [修复] 增加 -L 与双栈容灾 (-4),解决纯 V6 或 V6 优先机器连接 GitHub Raw 易超时的问题
|
||||||
TARGET_VERSION=${TARGET_VERSION:-"3.5.0"}
|
TARGET_VERSION=$( (curl -sL -m 5 "${REPO_RAW_URL}/version.txt" || curl -4 -sL -m 5 "${REPO_RAW_URL}/version.txt") 2>/dev/null | grep "^MASTER_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]')
|
||||||
|
|
||||||
|
# 🛡️ 兜底防线:如果网络波动拉取失败,启用内置的最新兜底版本
|
||||||
|
TARGET_VERSION=${TARGET_VERSION:-"4.0.0"}
|
||||||
|
|
||||||
MASTER_DIR="/opt/ip_sentinel_master"
|
MASTER_DIR="/opt/ip_sentinel_master"
|
||||||
DB_FILE="${MASTER_DIR}/sentinel.db"
|
DB_FILE="${MASTER_DIR}/sentinel.db"
|
||||||
@@ -23,56 +39,77 @@ echo "========================================================"
|
|||||||
echo " 🧠 欢迎使用 IP-Sentinel Master (控制中枢) v${TARGET_VERSION}"
|
echo " 🧠 欢迎使用 IP-Sentinel Master (控制中枢) v${TARGET_VERSION}"
|
||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
|
|
||||||
# [新增] 交互式操作菜单:支持选择部署或调用卸载程序
|
# ==========================================================
|
||||||
echo -e "\n请选择操作:"
|
# [v3.6.1 核心] 拦截司令部静默 OTA 升级模式 (强行接管执行流)
|
||||||
echo " 1) 🚀 部署 Master 控制中枢"
|
# ==========================================================
|
||||||
echo " 2) 🗑️ 一键卸载 Master 中枢"
|
if [ "$SILENT_MASTER_OTA" == "true" ]; then
|
||||||
read -p "请输入选择 [1-2] (默认1): " ACTION_CHOICE
|
echo -e "\n⏳ [OTA] 中枢重构指令已确认,正在剥离控制台交互..."
|
||||||
|
ACTION_CHOICE=1
|
||||||
if [ "$ACTION_CHOICE" == "2" ]; then
|
UPGRADE_MODE="true"
|
||||||
echo -e "\n⏳ 正在拉取卸载程序..."
|
KEEP_DB="true"
|
||||||
# [新增逻辑] 使用上面定义的 REPO_RAW_URL 动态拉取卸载脚本,执行后自动销毁临时文件
|
|
||||||
curl -sL "${REPO_RAW_URL}/master/uninstall_master.sh" -o "/tmp/uninstall_master.sh"
|
# 汲取原配置进入内存
|
||||||
chmod +x "/tmp/uninstall_master.sh"
|
if [ -f "${MASTER_DIR}/master.conf" ]; then
|
||||||
bash "/tmp/uninstall_master.sh"
|
|
||||||
rm -f "/tmp/uninstall_master.sh"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ================== [v3.2.2 新增: 平滑升级模式嗅探] ==================
|
|
||||||
UPGRADE_MODE="false"
|
|
||||||
KEEP_DB="true"
|
|
||||||
|
|
||||||
if [ "$ACTION_CHOICE" == "1" ] && [ -f "${MASTER_DIR}/master.conf" ]; then
|
|
||||||
echo -e "\n\033[33m💡 司令部雷达提示:检测到本机已部署过 Master 中枢。\033[0m"
|
|
||||||
read -p "👉 是否按原配置直接进行平滑升级?(y/n, 默认y): " UPGRADE_CHOICE
|
|
||||||
if [[ -z "$UPGRADE_CHOICE" || "$UPGRADE_CHOICE" =~ ^[Yy]$ ]]; then
|
|
||||||
UPGRADE_MODE="true"
|
|
||||||
read -p "👉 是否保留历史节点数据库 (SQLite)?(y/n, 默认y): " DB_CHOICE
|
|
||||||
if [[ "$DB_CHOICE" =~ ^[Nn]$ ]]; then
|
|
||||||
KEEP_DB="false"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 汲取原配置进入内存
|
|
||||||
source "${MASTER_DIR}/master.conf"
|
source "${MASTER_DIR}/master.conf"
|
||||||
|
|
||||||
# [v3.4.0 核心] 升级后立即同步/补录版本号至配置文件
|
# 同步新版本号至配置文件
|
||||||
if grep -q "^MASTER_VERSION=" "${MASTER_DIR}/master.conf"; then
|
if grep -q "^MASTER_VERSION=" "${MASTER_DIR}/master.conf"; then
|
||||||
sed -i "s/^MASTER_VERSION=.*/MASTER_VERSION=\"$TARGET_VERSION\"/" "${MASTER_DIR}/master.conf"
|
sed -i "s/^MASTER_VERSION=.*/MASTER_VERSION=\"$TARGET_VERSION\"/" "${MASTER_DIR}/master.conf"
|
||||||
else
|
else
|
||||||
echo "MASTER_VERSION=\"$TARGET_VERSION\"" >> "${MASTER_DIR}/master.conf"
|
echo "MASTER_VERSION=\"$TARGET_VERSION\"" >> "${MASTER_DIR}/master.conf"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
echo -e "\033[32m✅ 已激活 [平滑升级模式],版本已锚定为 v${TARGET_VERSION}...\033[0m"
|
echo -e "\033[32m✅ 已激活 [中枢静默重构模式],即将无损覆写内核...\033[0m"
|
||||||
else
|
else
|
||||||
echo -e "\033[33m🔄 您选择了重新配置,旧的中枢数据将被彻底抹除。\033[0m"
|
# [新增] 交互式操作菜单:支持选择部署或调用卸载程序
|
||||||
|
echo -e "\n请选择操作:"
|
||||||
|
echo " 1) 🚀 部署 Master 控制中枢"
|
||||||
|
echo " 2) 🗑️ 一键卸载 Master 中枢"
|
||||||
|
read -p "请输入选择 [1-2] (默认1): " ACTION_CHOICE
|
||||||
|
|
||||||
|
# [v3.5.2 修复] 防止用户直接回车导致变量为空,从而漏过下方的平滑升级判定被误删档
|
||||||
|
ACTION_CHOICE=${ACTION_CHOICE:-1}
|
||||||
|
|
||||||
|
if [ "$ACTION_CHOICE" == "2" ]; then
|
||||||
|
echo -e "\n⏳ 正在拉取卸载程序..."
|
||||||
|
curl -sL "${REPO_RAW_URL}/master/uninstall_master.sh" -o "${SECURE_TMP}/uninstall_master.sh"
|
||||||
|
chmod +x "${SECURE_TMP}/uninstall_master.sh"
|
||||||
|
bash "${SECURE_TMP}/uninstall_master.sh"
|
||||||
|
rm -f "/tmp/uninstall_master.sh"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ================== [v3.2.2 新增: 平滑升级模式嗅探] ==================
|
||||||
|
UPGRADE_MODE="false"
|
||||||
|
KEEP_DB="true"
|
||||||
|
|
||||||
|
if [ "$ACTION_CHOICE" == "1" ] && [ -f "${MASTER_DIR}/master.conf" ]; then
|
||||||
|
echo -e "\n\033[33m💡 司令部雷达提示:检测到本机已部署过 Master 中枢。\033[0m"
|
||||||
|
read -p "👉 是否按原配置直接进行平滑升级?(y/n, 默认y): " UPGRADE_CHOICE
|
||||||
|
if [[ -z "$UPGRADE_CHOICE" || "$UPGRADE_CHOICE" =~ ^[Yy]$ ]]; then
|
||||||
|
UPGRADE_MODE="true"
|
||||||
|
read -p "👉 是否保留历史节点数据库 (SQLite)?(y/n, 默认y): " DB_CHOICE
|
||||||
|
if [[ "$DB_CHOICE" =~ ^[Nn]$ ]]; then
|
||||||
|
KEEP_DB="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "${MASTER_DIR}/master.conf"
|
||||||
|
|
||||||
|
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
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# ====================================================================
|
|
||||||
|
|
||||||
# ================== [v3.2.2 优化: 安装前环境纯净度清理与数据保护] ==================
|
# ================== [v3.2.2 优化: 数据纯净度清理与保护] ==================
|
||||||
echo -e "\n⏳ 正在清理旧版 Master 守护进程..."
|
echo -e "\n⏳ 正在验证本地环境与数据..."
|
||||||
pkill -9 -f "tg_master.sh" >/dev/null 2>&1 || true
|
|
||||||
|
|
||||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||||
if [ "$KEEP_DB" == "false" ]; then
|
if [ "$KEEP_DB" == "false" ]; then
|
||||||
@@ -81,23 +118,76 @@ if [ "$UPGRADE_MODE" == "true" ]; then
|
|||||||
else
|
else
|
||||||
echo -e "📦 历史节点数据库 (SQLite) 已绝密保留。"
|
echo -e "📦 历史节点数据库 (SQLite) 已绝密保留。"
|
||||||
fi
|
fi
|
||||||
# 删除旧的核心脚本,准备拉取新的
|
# [防砖修复] 移除过早的旧进程抹杀与脚本物理删除,防止拉取失败导致司令部变砖失联
|
||||||
rm -f "${MASTER_DIR}/tg_master.sh" 2>/dev/null
|
|
||||||
else
|
else
|
||||||
# 焦土政策:如果不是升级模式,直接扬了整个司令部目录
|
# 焦土政策:如果不是升级模式,直接扬了整个司令部目录
|
||||||
rm -rf "$MASTER_DIR" 2>/dev/null
|
rm -rf "$MASTER_DIR" 2>/dev/null
|
||||||
fi
|
fi
|
||||||
echo -e "\033[32m✅ 旧进程已肃清!\033[0m"
|
|
||||||
# =======================================================================
|
# =======================================================================
|
||||||
|
|
||||||
# 1. 环境依赖安装
|
# 1. 依赖检查与智能安装 (v3.6.0 兼容性与优雅性升级)
|
||||||
echo -e "\n[1/4] 安装核心依赖 (curl, jq, sqlite3)..."
|
echo -e "\n[1/4] 正在探测核心依赖 (curl, jq, sqlite3, crontab, pgrep, openssl)..."
|
||||||
if [ -f /etc/debian_version ]; then
|
|
||||||
apt-get update -y >/dev/null 2>&1
|
REQUIRED_CMDS=("curl" "jq" "sqlite3" "crontab" "pgrep" "openssl")
|
||||||
apt-get install -y curl jq sqlite3 procps >/dev/null 2>&1
|
MISSING_CMDS=()
|
||||||
elif [ -f /etc/redhat-release ]; then
|
|
||||||
yum install -y curl jq sqlite >/dev/null 2>&1
|
# 基础探测:预检查缺失的命令
|
||||||
|
for cmd in "${REQUIRED_CMDS[@]}"; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
MISSING_CMDS+=("$cmd")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 如果有缺失,才执行包管理器拉取逻辑
|
||||||
|
if [ ${#MISSING_CMDS[@]} -gt 0 ]; then
|
||||||
|
echo "⏳ 发现缺失依赖: ${MISSING_CMDS[*]},正在尝试自动补齐..."
|
||||||
|
|
||||||
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
|
apt-get update -y >/dev/null 2>&1
|
||||||
|
# [v3.6.3 抽脂级优化] 注入 --no-install-recommends 拒绝捆绑销售
|
||||||
|
apt-get install -y --no-install-recommends curl jq sqlite3 cron procps openssl >/dev/null 2>&1
|
||||||
|
systemctl enable cron >/dev/null 2>&1 && systemctl start cron >/dev/null 2>&1
|
||||||
|
elif command -v yum >/dev/null 2>&1 || command -v dnf >/dev/null 2>&1; then
|
||||||
|
PKG_MGR="yum"
|
||||||
|
OPT_ARGS=""
|
||||||
|
if command -v dnf >/dev/null 2>&1; then
|
||||||
|
PKG_MGR="dnf"
|
||||||
|
# [v3.6.3 抽脂级优化] 强行关闭 DNF 的弱依赖拉取
|
||||||
|
OPT_ARGS="--setopt=install_weak_deps=False"
|
||||||
|
fi
|
||||||
|
$PKG_MGR install -y $OPT_ARGS curl jq sqlite cronie procps-ng openssl >/dev/null 2>&1
|
||||||
|
systemctl enable crond >/dev/null 2>&1 && systemctl start crond >/dev/null 2>&1
|
||||||
|
elif command -v apk >/dev/null 2>&1; then
|
||||||
|
echo "Alpine 探测到系统类型为 Alpine Linux,正在执行轻量级安装..."
|
||||||
|
# [修复] 优先尝试 cronie,若失败则回退至系统内置 cron,彻底避免单点依赖拖垮全局
|
||||||
|
apk add --no-cache curl jq sqlite cronie procps bash openssl || apk add --no-cache curl jq sqlite procps bash openssl
|
||||||
|
mkdir -p /var/spool/cron/crontabs
|
||||||
|
rc-update add crond default >/dev/null 2>&1
|
||||||
|
service crond start >/dev/null 2>&1
|
||||||
|
elif command -v pacman >/dev/null 2>&1; then
|
||||||
|
pacman -Sy --noconfirm curl jq sqlite cronie procps-ng openssl >/dev/null 2>&1
|
||||||
|
mkdir -p /root/.cache/crontab 2>/dev/null
|
||||||
|
systemctl enable cronie >/dev/null 2>&1 && systemctl start cronie >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
echo -e "\033[31m❌ 自动安装失败:系统未知的包管理器。\033[0m"
|
||||||
|
echo -e "\033[33m⚠️ 请手动执行以下安装命令后重新运行本脚本:\033[0m"
|
||||||
|
echo -e " Debian/Ubuntu: \033[36mapt-get update && apt-get install -y --no-install-recommends curl jq sqlite3 cron procps openssl\033[0m"
|
||||||
|
echo -e " CentOS/RHEL: \033[36myum install -y curl jq sqlite cronie procps-ng openssl\033[0m"
|
||||||
|
echo -e " Alpine Linux: \033[36mapk add --no-cache curl jq sqlite cronie procps bash openssl\033[0m"
|
||||||
|
echo -e " Arch Linux: \033[36mpacman -Sy curl jq sqlite cronie procps-ng openssl\033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 安装后二次复检
|
||||||
|
for cmd in "${REQUIRED_CMDS[@]}"; do
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo -e "\033[31m❌ 致命错误:核心命令 '$cmd' 仍未找到!\033[0m"
|
||||||
|
echo -e "请手动修复您的包管理器源,或联系 VPS 供应商。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
echo -e "\033[32m✅ 基础环境检测通过。\033[0m"
|
||||||
|
|
||||||
mkdir -p "$MASTER_DIR"
|
mkdir -p "$MASTER_DIR"
|
||||||
|
|
||||||
@@ -108,6 +198,32 @@ if [ "$UPGRADE_MODE" == "false" ]; then
|
|||||||
# 2. 交互配置机器人
|
# 2. 交互配置机器人
|
||||||
echo -e "\n[2/4] 配置控制中枢机器人:"
|
echo -e "\n[2/4] 配置控制中枢机器人:"
|
||||||
read -p "请输入 Telegram Bot Token: " TG_TOKEN
|
read -p "请输入 Telegram Bot Token: " TG_TOKEN
|
||||||
|
|
||||||
|
# [v3.6.0 新增] 官方网关模式选项 (用于屏蔽全局 OTA 按钮)
|
||||||
|
echo -e "\n请选择您的部署环境身份:"
|
||||||
|
echo " 1) 🛡️ 私有独立中枢 (默认推荐,保留完整 OTA 遥控权限)"
|
||||||
|
echo " 2) ☁️ 官方公共网关 (面向大众服务,将强制物理隐藏全局 OTA 按钮防滥用)"
|
||||||
|
read -p "请输入选择 [1-2] (默认1): " GATEWAY_TYPE
|
||||||
|
GATEWAY_TYPE=${GATEWAY_TYPE:-1}
|
||||||
|
|
||||||
|
IS_OFFICIAL_GATEWAY="false"
|
||||||
|
ENABLE_MASTER_OTA="false"
|
||||||
|
if [ "$GATEWAY_TYPE" == "2" ]; then
|
||||||
|
IS_OFFICIAL_GATEWAY="true"
|
||||||
|
echo -e "\033[33m⚠️ 已开启官方公共网关模式,全舰队与司令部的 OTA 将被强制屏蔽。\033[0m"
|
||||||
|
else
|
||||||
|
# [v3.6.1] 私有模式开放中枢 OTA 授权向导
|
||||||
|
echo -e "\n[2.1/4] 司令部自我进化授权"
|
||||||
|
echo -e "💡 开启后,您可以在 TG 菜单一键将中枢核心系统热更新至最新版本。"
|
||||||
|
read -p "是否允许司令部接收 OTA 重构指令?(y/n, 默认y): " M_OTA_CHOICE
|
||||||
|
if [[ "$M_OTA_CHOICE" =~ ^[Nn]$ ]]; then
|
||||||
|
ENABLE_MASTER_OTA="false"
|
||||||
|
echo -e "🛡️ \033[33m已关闭司令部 OTA 权限,中枢内核未来仅支持 SSH 升级。\033[0m"
|
||||||
|
else
|
||||||
|
ENABLE_MASTER_OTA="true"
|
||||||
|
echo -e "✅ \033[32m已开启司令部 OTA 权限,金蝉脱壳引信已挂载。\033[0m"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
cat > "${MASTER_DIR}/master.conf" << EOF
|
cat > "${MASTER_DIR}/master.conf" << EOF
|
||||||
# IP-Sentinel Master 本地固化配置 (v${TARGET_VERSION})
|
# IP-Sentinel Master 本地固化配置 (v${TARGET_VERSION})
|
||||||
@@ -115,11 +231,25 @@ MASTER_VERSION="$TARGET_VERSION"
|
|||||||
TG_TOKEN="$TG_TOKEN"
|
TG_TOKEN="$TG_TOKEN"
|
||||||
DB_FILE="$DB_FILE"
|
DB_FILE="$DB_FILE"
|
||||||
MASTER_DIR="$MASTER_DIR"
|
MASTER_DIR="$MASTER_DIR"
|
||||||
|
# [v3.6.0 核心] 官方网关 UI 熔断标识
|
||||||
|
IS_OFFICIAL_GATEWAY="$IS_OFFICIAL_GATEWAY"
|
||||||
|
# [v3.6.1 新增] 司令部自身 OTA 授权标识
|
||||||
|
ENABLE_MASTER_OTA="$ENABLE_MASTER_OTA"
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# [v3.6.1 热修复] 老司令部平滑升级时,自动补齐缺失字段
|
||||||
|
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||||
|
if ! grep -q "^IS_OFFICIAL_GATEWAY=" "${MASTER_DIR}/master.conf"; then
|
||||||
|
echo "IS_OFFICIAL_GATEWAY=\"false\"" >> "${MASTER_DIR}/master.conf"
|
||||||
|
fi
|
||||||
|
if ! grep -q "^ENABLE_MASTER_OTA=" "${MASTER_DIR}/master.conf"; then
|
||||||
|
echo "ENABLE_MASTER_OTA=\"false\"" >> "${MASTER_DIR}/master.conf"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# 🛑 拦截块结束
|
# 🛑 拦截块结束
|
||||||
|
|
||||||
# 3. 初始化 SQLite 数据库 (幂等操作,升级模式下可安全修补表结构)
|
# 3. 初始化 SQLite 数据库 (幂等操作,升级模式下由 tg_master.sh 负责热修补)
|
||||||
echo -e "\n[3/4] 正在初始化 SQLite 数据库表结构..."
|
echo -e "\n[3/4] 正在初始化 SQLite 数据库表结构..."
|
||||||
sqlite3 "$DB_FILE" <<EOF
|
sqlite3 "$DB_FILE" <<EOF
|
||||||
CREATE TABLE IF NOT EXISTS nodes (
|
CREATE TABLE IF NOT EXISTS nodes (
|
||||||
@@ -128,8 +258,24 @@ CREATE TABLE IF NOT EXISTS nodes (
|
|||||||
agent_ip TEXT,
|
agent_ip TEXT,
|
||||||
agent_port TEXT,
|
agent_port TEXT,
|
||||||
last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
|
last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
region TEXT DEFAULT 'UNKNOWN',
|
||||||
|
node_alias TEXT,
|
||||||
|
enable_google TEXT DEFAULT 'true',
|
||||||
|
enable_trust TEXT DEFAULT 'true',
|
||||||
|
enable_ota TEXT DEFAULT 'false',
|
||||||
PRIMARY KEY(chat_id, node_name)
|
PRIMARY KEY(chat_id, node_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- [v4.0.0 新增, v4.0.2 扩容] 核心情报表:记录历史 IP 质量数据,用于绘制趋势图
|
||||||
|
CREATE TABLE IF NOT EXISTS ip_trend_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
node_name TEXT,
|
||||||
|
check_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
scam_score INTEGER,
|
||||||
|
goog_status TEXT,
|
||||||
|
nf_status TEXT,
|
||||||
|
gpt_status TEXT
|
||||||
|
);
|
||||||
EOF
|
EOF
|
||||||
echo "✅ 数据库创建成功: $DB_FILE"
|
echo "✅ 数据库创建成功: $DB_FILE"
|
||||||
|
|
||||||
@@ -138,26 +284,88 @@ chmod 600 "${MASTER_DIR}/master.conf"
|
|||||||
chmod 600 "$DB_FILE"
|
chmod 600 "$DB_FILE"
|
||||||
# ====================================================================
|
# ====================================================================
|
||||||
|
|
||||||
# 4. 拉取核心调度代码并运行
|
# 4. 拉取核心调度代码并执行原子化交接
|
||||||
echo -e "\n[4/4] 部署 TG 调度守护进程..."
|
echo -e "\n[4/4] 正在拉取新版司令部核心引擎..."
|
||||||
# [修改] 剥离了写死的网址,改用顶部的 ${REPO_RAW_URL} 变量,确保与卸载脚本的数据源同源
|
|
||||||
curl -sL "${REPO_RAW_URL}/master/tg_master.sh" -o "${MASTER_DIR}/tg_master.sh"
|
TMP_MASTER="${SECURE_TMP}/tg_master.sh"
|
||||||
|
curl -sL "${REPO_RAW_URL}/master/tg_master.sh" -o "$TMP_MASTER"
|
||||||
|
|
||||||
|
# 🛡️ 防砖终极校验
|
||||||
|
if [ ! -s "$TMP_MASTER" ]; then
|
||||||
|
echo -e "\033[31m❌ 致命错误:中枢核心代码拉取失败!网络阻断或 GitHub Raw 异常。\033[0m"
|
||||||
|
echo "🛡️ 防砖机制触发:已中止覆盖,旧版司令部仍在安全运行中。"
|
||||||
|
rm -f "$TMP_MASTER"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 🟢 [原子化交接核心]: 校验完美通过,新代码已备妥!
|
||||||
|
# 以雷霆手段抹杀旧版调度进程,杜绝文件覆写时的并发错乱
|
||||||
|
echo "⏳ 新引擎校验通过,正在抹杀旧版守护进程..."
|
||||||
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
systemctl kill --signal=SIGKILL ip-sentinel-master.service >/dev/null 2>&1 || true
|
||||||
|
systemctl stop ip-sentinel-master.service >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
pkill -9 -f "tg_master.sh" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# 执行物理替换
|
||||||
|
mv "$TMP_MASTER" "${MASTER_DIR}/tg_master.sh"
|
||||||
chmod +x "${MASTER_DIR}/tg_master.sh"
|
chmod +x "${MASTER_DIR}/tg_master.sh"
|
||||||
|
|
||||||
# 写入看门狗 Cron
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
crontab -l 2>/dev/null | grep -v "tg_master.sh" > /tmp/cron_master
|
echo "💡 检测到 Systemd 环境,正在部署原生守护服务..."
|
||||||
echo "* * * * * pgrep -f tg_master.sh >/dev/null || nohup bash ${MASTER_DIR}/tg_master.sh >/dev/null 2>&1 &" >> /tmp/cron_master
|
|
||||||
crontab /tmp/cron_master
|
cat > /etc/systemd/system/ip-sentinel-master.service << EOF
|
||||||
rm -f /tmp/cron_master
|
[Unit]
|
||||||
|
Description=IP-Sentinel Master Command Center Service
|
||||||
|
After=network.target
|
||||||
|
|
||||||
# 立刻启动
|
[Service]
|
||||||
pgrep -f tg_master.sh >/dev/null || nohup bash "${MASTER_DIR}/tg_master.sh" >/dev/null 2>&1 &
|
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
SyslogIdentifier=ip-sentinel
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/bin/bash ${MASTER_DIR}/tg_master.sh
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=${MASTER_DIR}
|
||||||
|
CPUSchedulingPolicy=idle
|
||||||
|
IOSchedulingClass=idle
|
||||||
|
|
||||||
# ================== [v3.2.2 优化: 战报文案分流] ==================
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable --now ip-sentinel-master.service
|
||||||
|
systemctl restart ip-sentinel-master.service
|
||||||
|
|
||||||
|
# 清理可能残留的历史 Cron (无落地内存流防劫持)
|
||||||
|
crontab -l 2>/dev/null | grep -v "tg_master.sh" | crontab - >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
|
echo "💡 未检测到 Systemd,回退到 Cron 看门狗调度模式..."
|
||||||
|
crontab -l 2>/dev/null | grep -v "tg_master.sh" > "${SECURE_TMP}/cron_master" || true
|
||||||
|
echo "* * * * * pgrep -f tg_master.sh >/dev/null || nohup bash ${MASTER_DIR}/tg_master.sh >/dev/null 2>&1 &" >> "${SECURE_TMP}/cron_master"
|
||||||
|
[ -f "${SECURE_TMP}/cron_master" ] && crontab "${SECURE_TMP}/cron_master" 2>/dev/null
|
||||||
|
|
||||||
|
pgrep -f tg_master.sh >/dev/null || { nohup bash "${MASTER_DIR}/tg_master.sh" >/dev/null 2>&1 & disown 2>/dev/null; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ================== [v3.2.2 优化 & v3.6.1 OTA捷报: 战报文案分流] ==================
|
||||||
echo "========================================================"
|
echo "========================================================"
|
||||||
if [ "$UPGRADE_MODE" == "true" ]; then
|
if [ "$UPGRADE_MODE" == "true" ]; then
|
||||||
echo "🎉 Master 控制中枢平滑热更新完成!"
|
echo "🎉 Master 控制中枢平滑热更新完成!"
|
||||||
echo "🤖 新版中枢引擎已接管数据库,继续等待边缘节点汇报。"
|
echo "🤖 新版中枢引擎已接管数据库,继续等待边缘节点汇报。"
|
||||||
|
|
||||||
|
# [v3.6.1 核心] 静默 OTA 完成后,由幽灵进程主动向指挥官发送捷报
|
||||||
|
if [ "$SILENT_MASTER_OTA" == "true" ] && [ -n "$OTA_CHAT_ID" ] && [ -n "$TG_TOKEN" ]; then
|
||||||
|
echo -e "\n📡 正在向指挥官发送司令部重构捷报..."
|
||||||
|
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
||||||
|
-d "chat_id=${OTA_CHAT_ID}" \
|
||||||
|
-d "parse_mode=Markdown" \
|
||||||
|
-d "text=✨ *司令部中枢热重载完成!*
|
||||||
|
🚀 当前内核已跃升至:\`v${TARGET_VERSION}\`
|
||||||
|
🤖 新版金蝉脱壳引擎已接管阵地,全舰队指控链路恢复正常。" > /dev/null
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
echo "🎉 Master 控制中枢部署完成!"
|
echo "🎉 Master 控制中枢部署完成!"
|
||||||
echo "🤖 机器人现已开始全局接客,等待边缘节点注册。"
|
echo "🤖 机器人现已开始全局接客,等待边缘节点注册。"
|
||||||
@@ -166,12 +374,15 @@ echo "========================================================"
|
|||||||
# =================================================================
|
# =================================================================
|
||||||
|
|
||||||
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
|
# ================== [v3.1.2 新增: 玻璃房透明装机统计] ==================
|
||||||
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名,不收集IP)..."
|
# [修复] 仅在全新部署时触发统计,司令部热重载时绝对不触发
|
||||||
MASTER_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/master" || echo "")
|
if [ "$UPGRADE_MODE" == "false" ]; then
|
||||||
|
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名,不收集IP)..."
|
||||||
|
MASTER_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/master" || echo "")
|
||||||
|
|
||||||
if [ -n "$MASTER_COUNT" ] && [[ "$MASTER_COUNT" =~ ^[0-9]+$ ]]; then
|
if [ -n "$MASTER_COUNT" ] && [[ "$MASTER_COUNT" =~ ^[0-9]+$ ]]; then
|
||||||
echo -e "\033[32m✅ 感谢您成为全球第 ${MASTER_COUNT} 名 IP-Sentinel 指挥官!\033[0m"
|
echo -e "\033[32m✅ 感谢您成为全球第 ${MASTER_COUNT} 名 IP-Sentinel 指挥官!\033[0m"
|
||||||
else
|
else
|
||||||
echo -e "\033[32m✅ 感谢您建立 IP-Sentinel 司令部!\033[0m"
|
echo -e "\033[32m✅ 感谢您建立 IP-Sentinel 司令部!\033[0m"
|
||||||
|
fi
|
||||||
|
echo -e "\n"
|
||||||
fi
|
fi
|
||||||
echo -e "\n"
|
|
||||||
@@ -11,6 +11,7 @@ source "$CONF"
|
|||||||
|
|
||||||
# [核心: 运行态版本继承与云通信地址]
|
# [核心: 运行态版本继承与云通信地址]
|
||||||
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
REPO_RAW_URL="https://raw.githubusercontent.com/hotyue/IP-Sentinel/main"
|
||||||
|
|
||||||
# MASTER_VERSION 已经在上方的 source "$CONF" 中被载入
|
# MASTER_VERSION 已经在上方的 source "$CONF" 中被载入
|
||||||
# 如果本地极度陈旧没有该变量,才给定一个基础兜底值,避免变量为空导致崩溃
|
# 如果本地极度陈旧没有该变量,才给定一个基础兜底值,避免变量为空导致崩溃
|
||||||
MASTER_VERSION=${MASTER_VERSION:-"3.5.0"}
|
MASTER_VERSION=${MASTER_VERSION:-"3.5.0"}
|
||||||
@@ -19,26 +20,53 @@ OFFSET_FILE="${MASTER_DIR}/.tg_offset"
|
|||||||
[[ -f $OFFSET_FILE ]] || echo "0" > $OFFSET_FILE
|
[[ -f $OFFSET_FILE ]] || echo "0" > $OFFSET_FILE
|
||||||
|
|
||||||
# --- 工具函数 ---
|
# --- 工具函数 ---
|
||||||
|
# ================== [v4.0.3 核心: 全球全能旗帜渲染引擎] ==================
|
||||||
|
get_flag() {
|
||||||
|
local region=$(echo "$1" | tr 'a-z' 'A-Z')
|
||||||
|
local base_cc="${region%%-*}" # 提取横杠前的主国家代码 (例如 US-TX 提取为 US)
|
||||||
|
local flag="🌐"
|
||||||
|
case "$base_cc" in
|
||||||
|
US) flag="🇺🇸" ;; JP) flag="🇯🇵" ;; HK) flag="🇭🇰" ;; TW) flag="🇹🇼" ;; SG) flag="🇸🇬" ;;
|
||||||
|
UK|GB) flag="🇬🇧" ;; DE) flag="🇩🇪" ;; FR) flag="🇫🇷" ;; NL) flag="🇳🇱" ;; CA) flag="🇨🇦" ;;
|
||||||
|
AU) flag="🇦🇺" ;; KR) flag="🇰🇷" ;; IN) flag="🇮🇳" ;; BR) flag="🇧🇷" ;; RU) flag="🇷🇺" ;;
|
||||||
|
CH) flag="🇨🇭" ;; SE) flag="🇸🇪" ;; NO) flag="🇳🇴" ;; DK) flag="🇩🇰" ;; FI) flag="🇫🇮" ;;
|
||||||
|
IT) flag="🇮🇹" ;; ES) flag="🇪🇸" ;; PT) flag="🇵🇹" ;; IE) flag="🇮🇪" ;; PL) flag="🇵🇱" ;;
|
||||||
|
AT) flag="🇦🇹" ;; BE) flag="🇧🇪" ;; TR) flag="🇹🇷" ;; ZA) flag="🇿🇦" ;; AE) flag="🇦🇪" ;;
|
||||||
|
MY) flag="🇲🇾" ;; ID) flag="🇮🇩" ;; VN) flag="🇻🇳" ;; TH) flag="🇹🇭" ;; PH) flag="🇵🇭" ;;
|
||||||
|
NZ) flag="🇳🇿" ;; AR) flag="🇦🇷" ;; CL) flag="🇨🇱" ;; MX) flag="🇲🇽" ;; IL) flag="🇮🇱" ;;
|
||||||
|
SA) flag="🇸🇦" ;; EG) flag="🇪🇬" ;; NG) flag="🇳🇬" ;; KE) flag="🇰🇪" ;; RO) flag="🇷🇴" ;;
|
||||||
|
BG) flag="🇧🇬" ;; CZ) flag="🇨🇿" ;; HU) flag="🇭🇺" ;; GR) flag="🇬🇷" ;; UA) flag="🇺🇦" ;;
|
||||||
|
esac
|
||||||
|
echo "$flag"
|
||||||
|
}
|
||||||
|
|
||||||
send_ui() {
|
send_ui() {
|
||||||
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "{\"chat_id\":\"$1\",\"text\":\"$2\",\"parse_mode\":\"Markdown\",\"reply_markup\":{\"inline_keyboard\":$3}}" > /dev/null
|
-d "{\"chat_id\":\"$1\",\"text\":\"$2\",\"parse_mode\":\"Markdown\",\"reply_markup\":{\"inline_keyboard\":$3}}" > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
send_msg() {
|
send_msg() {
|
||||||
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
||||||
-d "chat_id=$1" -d "text=$2" -d "parse_mode=Markdown" > /dev/null
|
-d "chat_id=$1" -d "text=$2" -d "parse_mode=Markdown" > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# ================== [v3.0.1 新增: 消息原位刷新函数] ==================
|
# ================== [v3.0.1 新增: 消息原位刷新函数] ==================
|
||||||
edit_msg() {
|
edit_msg() {
|
||||||
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/editMessageText" \
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/editMessageText" \
|
||||||
-d "chat_id=$1" -d "message_id=$2" -d "text=$3" -d "parse_mode=Markdown" > /dev/null
|
-d "chat_id=$1" -d "message_id=$2" -d "text=$3" -d "parse_mode=Markdown" > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# 数据库执行函数
|
# [v3.5.3 新增: 支持内联键盘的原位 UI 重绘函数]
|
||||||
|
edit_ui() {
|
||||||
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/editMessageText" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"chat_id\":\"$1\",\"message_id\":\"$2\",\"text\":\"$3\",\"parse_mode\":\"Markdown\",\"reply_markup\":{\"inline_keyboard\":$4}}" > /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# 数据库执行函数 (v3.6.3 终极静默版: 动用 .timeout 点命令防泄露)
|
||||||
db_exec() {
|
db_exec() {
|
||||||
sqlite3 "$DB_FILE" "$1"
|
printf ".timeout 5000\n%s\n" "$1" | sqlite3 "$DB_FILE"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ================== [v3.0.4 核心: 动态 HMAC 签名生成器] ==================
|
# ================== [v3.0.4 核心: 动态 HMAC 签名生成器] ==================
|
||||||
@@ -56,19 +84,41 @@ generate_signed_url() {
|
|||||||
local signature=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$CHAT_ID" | awk '{print $NF}')
|
local signature=$(echo -n "$payload" | openssl dgst -sha256 -hmac "$CHAT_ID" | awk '{print $NF}')
|
||||||
|
|
||||||
# 返回最终带签名的 URL
|
# 返回最终带签名的 URL
|
||||||
echo "http://${target_ip}:${target_port}${action_path}?t=${current_t}&sign=${signature}"
|
echo "https://${target_ip}:${target_port}${action_path}?t=${current_t}&sign=${signature}"
|
||||||
}
|
}
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
# ================== [v3.1.3 核心: 数据库结构无损热升级] ==================
|
# ================== [v3.6.3 核心: 激活 SQLite 高并发 WAL 引擎] ==================
|
||||||
# 自动探测并增加 region 字段,屏蔽已存在的报错,保护老节点数据
|
db_exec "PRAGMA journal_mode=WAL;" > /dev/null 2>&1
|
||||||
|
db_exec "PRAGMA synchronous=NORMAL;" > /dev/null 2>&1
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
# ================== [v3.1.3-v3.6.0 核心: 数据库结构无损热升级] ==================
|
||||||
|
# 自动探测并增加缺失字段,屏蔽已存在的报错,保护老节点数据
|
||||||
db_exec "ALTER TABLE nodes ADD COLUMN region TEXT DEFAULT 'UNKNOWN';" 2>/dev/null
|
db_exec "ALTER TABLE nodes ADD COLUMN region TEXT DEFAULT 'UNKNOWN';" 2>/dev/null
|
||||||
|
db_exec "ALTER TABLE nodes ADD COLUMN node_alias TEXT;" 2>/dev/null
|
||||||
|
db_exec "ALTER TABLE nodes ADD COLUMN enable_google TEXT DEFAULT 'true';" 2>/dev/null
|
||||||
|
db_exec "ALTER TABLE nodes ADD COLUMN enable_trust TEXT DEFAULT 'true';" 2>/dev/null
|
||||||
|
db_exec "ALTER TABLE nodes ADD COLUMN enable_ota TEXT DEFAULT 'false';" 2>/dev/null
|
||||||
|
# ========================================================================
|
||||||
|
|
||||||
|
# ================== [v4.0.0/v4.0.2 核心: 增加 IP 质量趋势追踪表] ==================
|
||||||
|
db_exec "CREATE TABLE IF NOT EXISTS ip_trend_log (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
node_name TEXT,
|
||||||
|
check_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
scam_score INTEGER,
|
||||||
|
nf_status TEXT
|
||||||
|
);" 2>/dev/null
|
||||||
|
# [v4.0.2 热更新] 动态扩容 谷歌 与 ChatGPT 状态追踪字段
|
||||||
|
db_exec "ALTER TABLE ip_trend_log ADD COLUMN goog_status TEXT DEFAULT 'Unknown';" 2>/dev/null
|
||||||
|
db_exec "ALTER TABLE ip_trend_log ADD COLUMN gpt_status TEXT DEFAULT 'Unknown';" 2>/dev/null
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
|
|
||||||
# --- 核心轮询循环 ---
|
# --- 核心轮询循环 ---
|
||||||
while true; do
|
while true; do
|
||||||
OFFSET=$(cat $OFFSET_FILE)
|
OFFSET=$(cat $OFFSET_FILE)
|
||||||
UPDATES=$(curl -s "https://api.telegram.org/bot${TG_TOKEN}/getUpdates?offset=${OFFSET}&timeout=30")
|
UPDATES=$(curl -s --connect-timeout 5 -m 35 "https://api.telegram.org/bot${TG_TOKEN}/getUpdates?offset=${OFFSET}&timeout=30")
|
||||||
|
|
||||||
COUNT=$(echo "$UPDATES" | jq -r '.result | length' 2>/dev/null)
|
COUNT=$(echo "$UPDATES" | jq -r '.result | length' 2>/dev/null)
|
||||||
|
|
||||||
@@ -80,13 +130,77 @@ while true; do
|
|||||||
CHAT_ID=$(echo "$UPDATE" | jq -r '.message.chat.id // .callback_query.message.chat.id')
|
CHAT_ID=$(echo "$UPDATE" | jq -r '.message.chat.id // .callback_query.message.chat.id')
|
||||||
TEXT=$(echo "$UPDATE" | jq -r '.message.text // .callback_query.data')
|
TEXT=$(echo "$UPDATE" | jq -r '.message.text // .callback_query.data')
|
||||||
|
|
||||||
# ================== [v3.0.1 新增: 消除转圈圈与获取消息ID] ==================
|
# ================== [基础消息解析提取提前] ==================
|
||||||
|
# [致命 Bug 修复] 必须在 svq 入库判断前提取这俩变量,否则入库后无法重绘 UI
|
||||||
CB_ID=$(echo "$UPDATE" | jq -r '.callback_query.id // empty')
|
CB_ID=$(echo "$UPDATE" | jq -r '.callback_query.id // empty')
|
||||||
MSG_ID=$(echo "$UPDATE" | jq -r '.callback_query.message.message_id // empty')
|
MSG_ID=$(echo "$UPDATE" | jq -r '.callback_query.message.message_id // empty')
|
||||||
|
|
||||||
|
# ================== [v4.0.2 核心: 态势感知按钮一键入库] ==================
|
||||||
|
if [[ "$TEXT" == "svq|"* ]]; then
|
||||||
|
# 格式: svq|NODE_NAME|SCORE|GOOG|NF|GPT
|
||||||
|
IFS='|' read -r MAGIC RAW_NODE_ID RAW_SCORE RAW_GOOG_ST RAW_NF_ST RAW_GPT_ST <<< "$TEXT"
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
# 🛡️ 终极防御:彻底清洗,封死一切 SQL 注入通道
|
||||||
|
NODE_ID=$(echo "$RAW_NODE_ID" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
SCORE=$(echo "$RAW_SCORE" | tr -cd '0-9')
|
||||||
|
GOOG_ST=$(echo "$RAW_GOOG_ST" | tr -d '"'\''\`\$\|&;<>\n\r')
|
||||||
|
NF_ST=$(echo "$RAW_NF_ST" | tr -d '"'\''\`\$\|&;<>\n\r')
|
||||||
|
GPT_ST=$(echo "$RAW_GPT_ST" | tr -d '"'\''\`\$\|&;<>\n\r')
|
||||||
|
|
||||||
|
if [ -n "$NODE_ID" ] && [ -n "$SCORE" ]; then
|
||||||
|
# 1. 写入 SQLite
|
||||||
|
db_exec "INSERT INTO ip_trend_log (node_name, scam_score, goog_status, nf_status, gpt_status) VALUES ('$NODE_ID', '$SCORE', '$GOOG_ST', '$NF_ST', '$GPT_ST');"
|
||||||
|
|
||||||
|
# [体验优化] 弹出顶部 Toast 气泡,提示入库成功
|
||||||
|
if [ -n "$CB_ID" ]; then
|
||||||
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/answerCallbackQuery" \
|
||||||
|
-d "callback_query_id=${CB_ID}" \
|
||||||
|
-d "text=✅ 报告已成功录入趋势库!" \
|
||||||
|
-d "show_alert=false" > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 无损修改原消息:移除入库按钮展示绿勾状态,并保留返回控制台按钮 (体验优化)
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/editMessageReplyMarkup" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"chat_id\":\"${CHAT_ID}\",\"message_id\":\"${MSG_ID}\",\"reply_markup\":{\"inline_keyboard\":[[{\"text\":\"✅ 此报告已存档\",\"callback_data\":\"ignore\"}],[{\"text\":\"⚙️ 调出该节点控制台\",\"callback_data\":\"manage:${NODE_ID}\"}]]}}" > /dev/null
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# [异常兜底] 弹出红色警告弹窗
|
||||||
|
if [ -n "$CB_ID" ]; then
|
||||||
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/answerCallbackQuery" \
|
||||||
|
-d "callback_query_id=${CB_ID}" \
|
||||||
|
-d "text=❌ 数据解析失败,入库中止。" \
|
||||||
|
-d "show_alert=true" > /dev/null
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# ======================================================================
|
||||||
|
|
||||||
# 告诉 TG 官方“指令已收到”,立刻消除按钮上的加载圈圈
|
REPLY_TO_TEXT=$(echo "$UPDATE" | jq -r '.message.reply_to_message.text // empty')
|
||||||
|
|
||||||
|
# ================== [v3.5.2 新增: 拦截别名修改的对话回复] ==================
|
||||||
|
if [[ "$REPLY_TO_TEXT" == *"✏️ 请回复本消息以重命名节点:"* ]]; then
|
||||||
|
# 精准提取被回复消息中的节点主键名
|
||||||
|
TARGET_NODE=$(echo "$REPLY_TO_TEXT" | grep -v "✏️" | grep -v "仅限" | tr -d '\` ' | tr -cd 'a-zA-Z0-9_.-' | head -n 1)
|
||||||
|
|
||||||
|
# [v3.5.2 热修复] 废除 Bash 原生 tr 命令的中文白名单 (不支持 Unicode 会误删中文)。
|
||||||
|
# 改用黑名单策略:仅自动转化下划线,剔除引号、特殊符号和冒号(防止破坏内部路由),
|
||||||
|
# 将完整的中文原样送入 Base64 编码,最终严格正则清洗交由 Agent 的 Python 引擎处理!
|
||||||
|
NEW_ALIAS=$(echo "$TEXT" | sed 's/_/-/g' | tr -d '"'\''\`\$\|&;<>\n\r:' | cut -c 1-30)
|
||||||
|
|
||||||
|
if [ -n "$TARGET_NODE" ] && [ -n "$NEW_ALIAS" ]; then
|
||||||
|
# 强行重写内部路由
|
||||||
|
TEXT="do_rename:${TARGET_NODE}:${NEW_ALIAS}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ================== [v3.0.1 新增: 消除转圈圈与获取消息ID] ==================
|
||||||
|
# 告诉 TG 官方“指令已收到”,立刻消除按钮上的加载圈圈 (对其他常规按钮生效)
|
||||||
if [ -n "$CB_ID" ]; then
|
if [ -n "$CB_ID" ]; then
|
||||||
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/answerCallbackQuery" -d "callback_query_id=${CB_ID}" > /dev/null
|
curl -s --connect-timeout 5 -m 10 -X POST "https://api.telegram.org/bot${TG_TOKEN}/answerCallbackQuery" -d "callback_query_id=${CB_ID}" > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
@@ -95,21 +209,34 @@ while true; do
|
|||||||
if [[ "$TEXT" == *"#REGISTER#"* ]]; then
|
if [[ "$TEXT" == *"#REGISTER#"* ]]; then
|
||||||
REG_LINE=$(echo "$TEXT" | grep "#REGISTER#" | head -n 1 | tr -d '\` ')
|
REG_LINE=$(echo "$TEXT" | grep "#REGISTER#" | head -n 1 | tr -d '\` ')
|
||||||
|
|
||||||
# V3.1.3 兼容性拆包: 判断是新版协议 (5个字段) 还是老版协议 (4个字段)
|
# V3.6.0 兼容性拆包: 支持 7字段(OTA)、6字段(双轨)、5字段(单轨)、4字段(远古)
|
||||||
FIELD_COUNT=$(echo "$REG_LINE" | awk -F'|' '{print NF}')
|
FIELD_COUNT=$(echo "$REG_LINE" | awk -F'|' '{print NF}')
|
||||||
if [ "$FIELD_COUNT" -ge 5 ]; then
|
if [ "$FIELD_COUNT" -ge 7 ]; then
|
||||||
|
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT RAW_ALIAS RAW_OTA <<< "$REG_LINE"
|
||||||
|
elif [ "$FIELD_COUNT" -eq 6 ]; then
|
||||||
|
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT RAW_ALIAS <<< "$REG_LINE"
|
||||||
|
RAW_OTA="false"
|
||||||
|
elif [ "$FIELD_COUNT" -eq 5 ]; then
|
||||||
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
IFS='|' read -r MAGIC RAW_REGION RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
||||||
|
RAW_ALIAS="$RAW_NODE"
|
||||||
|
RAW_OTA="false"
|
||||||
else
|
else
|
||||||
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
IFS='|' read -r MAGIC RAW_NODE RAW_IP RAW_PORT <<< "$REG_LINE"
|
||||||
RAW_REGION="UNKNOWN"
|
RAW_REGION="UNKNOWN"
|
||||||
|
RAW_ALIAS="$RAW_NODE"
|
||||||
|
RAW_OTA="false"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 🛡️ 强制字符白名单过滤:保留历史特征不变
|
# 🛡️ 强制字符白名单过滤:保留历史特征不变
|
||||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
AGENT_REGION=$(echo "$RAW_REGION" | tr -cd 'a-zA-Z0-9' | cut -c 1-10) # 提取国家大区
|
AGENT_REGION=$(echo "$RAW_REGION" | tr -cd 'a-zA-Z0-9' | cut -c 1-10)
|
||||||
NODE_NAME=$(echo "$RAW_NODE" | tr -cd 'a-zA-Z0-9_.-' | cut -c 1-30)
|
NODE_NAME=$(echo "$RAW_NODE" | tr -cd 'a-zA-Z0-9_.-' | cut -c 1-30)
|
||||||
AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-' | cut -c 1-50)
|
AGENT_IP=$(echo "$RAW_IP" | tr -cd 'a-zA-Z0-9.:\[\]-' | cut -c 1-50)
|
||||||
AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5)
|
AGENT_PORT=$(echo "$RAW_PORT" | tr -cd '0-9' | cut -c 1-5)
|
||||||
|
NODE_ALIAS=$(echo "$RAW_ALIAS" | tr -d '"'\''\`\$\|&;<>\n\r' | cut -c 1-30)
|
||||||
|
[ -z "$NODE_ALIAS" ] && NODE_ALIAS="$NODE_NAME"
|
||||||
|
AGENT_OTA=$(echo "$RAW_OTA" | tr -cd 'a-z')
|
||||||
|
[ -z "$AGENT_OTA" ] && AGENT_OTA="false"
|
||||||
|
|
||||||
if [[ "$AGENT_IP" =~ ^127\.|^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^::1$|^localhost$ ]]; then
|
if [[ "$AGENT_IP" =~ ^127\.|^10\.|^192\.168\.|^172\.(1[6-9]|2[0-9]|3[0-1])\.|^::1$|^localhost$ ]]; then
|
||||||
send_msg "$CHAT_ID" "⛔ **安全拦截**:禁止注册内网或回环 IP,防止 SSRF 攻击渗透。"
|
send_msg "$CHAT_ID" "⛔ **安全拦截**:禁止注册内网或回环 IP,防止 SSRF 攻击渗透。"
|
||||||
@@ -121,9 +248,9 @@ while true; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 入库时追加 region 字段
|
# [核心] 入库时追加 node_alias 与 enable_ota 字段
|
||||||
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';"
|
db_exec "INSERT INTO nodes (chat_id, node_name, agent_ip, agent_port, last_seen, region, node_alias, enable_ota) VALUES ('$CHAT_ID', '$NODE_NAME', '$AGENT_IP', '$AGENT_PORT', CURRENT_TIMESTAMP, '$AGENT_REGION', '$NODE_ALIAS', '$AGENT_OTA') ON CONFLICT(chat_id, node_name) DO UPDATE SET agent_ip='$AGENT_IP', agent_port='$AGENT_PORT', last_seen=CURRENT_TIMESTAMP, region='$AGENT_REGION', node_alias='$NODE_ALIAS', enable_ota='$AGENT_OTA';"
|
||||||
send_msg "$CHAT_ID" "✅ **司令部确认 (v${MASTER_VERSION})**\n节点接入成功: \`$NODE_NAME\`\n地址: \`$AGENT_IP:$AGENT_PORT\`"
|
send_msg "$CHAT_ID" "✅ **司令部确认 (v${MASTER_VERSION})**%0A节点 \`${NODE_ALIAS}\` 档案已录入!"
|
||||||
|
|
||||||
# ================== [v3.1.3 丝滑连招: 直接呼出全球大区雷达] ==================
|
# ================== [v3.1.3 丝滑连招: 直接呼出全球大区雷达] ==================
|
||||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||||
@@ -131,12 +258,7 @@ while true; do
|
|||||||
BTNS="["
|
BTNS="["
|
||||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||||
FLAG="🌐"
|
FLAG=$(get_flag "$REGION_NAME")
|
||||||
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\"}],"
|
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||||
done <<< "$REGION_DATA"
|
done <<< "$REGION_DATA"
|
||||||
BTNS="${BTNS%,}]"
|
BTNS="${BTNS%,}]"
|
||||||
@@ -152,16 +274,97 @@ while true; do
|
|||||||
# ==========================================
|
# ==========================================
|
||||||
case "$TEXT" in
|
case "$TEXT" in
|
||||||
"/start"|"/menu")
|
"/start"|"/menu")
|
||||||
# [v3.4.0 核心] 抓取云端最新版本
|
# [核心: 抓取云端最新 Master 版本 (KV 解析法)]
|
||||||
REMOTE_VER=$(curl -s -m 2 "${REPO_RAW_URL}/version.txt" | tr -d '[:space:]')
|
REMOTE_VER=$(curl -s -m 2 "${REPO_RAW_URL}/version.txt" | grep "^MASTER_VERSION=" | cut -d'=' -f2 | tr -d '[:space:]')
|
||||||
VER_INFO="当前版本: \`v${MASTER_VERSION}\`"
|
VER_INFO="当前版本: \`v${MASTER_VERSION}\`"
|
||||||
|
|
||||||
|
BTN_MASTER_OTA=""
|
||||||
if [ -n "$REMOTE_VER" ] && [ "$REMOTE_VER" != "$MASTER_VERSION" ]; then
|
if [ -n "$REMOTE_VER" ] && [ "$REMOTE_VER" != "$MASTER_VERSION" ]; then
|
||||||
VER_INFO="${VER_INFO}\n✨ **发现新版本**: \`v${REMOTE_VER}\` (请尽快更新主控)"
|
VER_INFO="${VER_INFO}\n✨ **发现新版本**: \`v${REMOTE_VER}\` (可执行中枢热重载)"
|
||||||
|
|
||||||
|
# 仅当非官方网关 且 开启了中枢 OTA 权限时,才渲染升级按钮
|
||||||
|
if [ "$IS_OFFICIAL_GATEWAY" != "true" ] && [ "${ENABLE_MASTER_OTA:-false}" == "true" ]; then
|
||||||
|
BTN_MASTER_OTA="[{\"text\":\"🆙 升级司令部至 v${REMOTE_VER}\",\"callback_data\":\"master_ota_confirm\"}],"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
BTNS="[[{\"text\":\"🖥️ 我的节点列表\",\"callback_data\":\"list_nodes\"}], [{\"text\":\"🚀 全节点日报汇总\",\"callback_data\":\"all_reports\"}], [{\"text\":\"🛠️ 全节点一键维护\",\"callback_data\":\"all_run\"}]]"
|
NODE_COUNT=$(db_exec "SELECT COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID';")
|
||||||
send_ui "$CHAT_ID" "🛡️ **IP-Sentinel 司令部**\n${VER_INFO}\n\n欢迎回来,长官。请下达指令:" "$BTNS"
|
[ -z "$NODE_COUNT" ] && NODE_COUNT=0
|
||||||
|
|
||||||
|
# L0 扁平化重构:将司令部升级按钮动态置于最顶层
|
||||||
|
if [ "$IS_OFFICIAL_GATEWAY" != "true" ]; then
|
||||||
|
BTNS="[${BTN_MASTER_OTA}[{\"text\":\"🌍 进入全球战区雷达 (管理节点)\",\"callback_data\":\"list_nodes\"}], [{\"text\":\"🚀 全军总攻\",\"callback_data\":\"all_run\"}, {\"text\":\"📊 全军简报\",\"callback_data\":\"all_reports\"}], [{\"text\":\"☢️ 全舰队 OTA 热重载\",\"callback_data\":\"all_ota_confirm\"}]]"
|
||||||
|
else
|
||||||
|
BTNS="[[{\"text\":\"🌍 进入全球战区雷达 (管理节点)\",\"callback_data\":\"list_nodes\"}], [{\"text\":\"🚀 全军总攻\",\"callback_data\":\"all_run\"}, {\"text\":\"📊 全军简报\",\"callback_data\":\"all_reports\"}]]"
|
||||||
|
fi
|
||||||
|
TEXT_MSG="🛡️ **IP-Sentinel 司令部**\n${VER_INFO}\n\n📊 舰队状态: 共有 \`${NODE_COUNT}\` 台哨兵在线\n欢迎回来,长官。请下达战略指令:"
|
||||||
|
send_ui "$CHAT_ID" "$TEXT_MSG" "$BTNS"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"all_ota_confirm")
|
||||||
|
CONFIRM_BTNS="[[{\"text\":\"🚨 我已了解风险,下发核按钮指令!\",\"callback_data\":\"all_ota_execute\"}], [{\"text\":\"取消操作\",\"callback_data\":\"/start\"}]]"
|
||||||
|
WARNING_MSG="☢️ **【最高指令:全舰队 OTA 升级】**\n\n此操作将向您名下**所有开启 OTA 权限的节点**下发重组指令,强制从云端拉取最新代码并进行热重载。\n\n⚠️ **核按钮风险提示**:\n1. 升级过程中守护进程会短暂重启,节点可能出现临时离线。\n2. 若遇 GitHub 源屏蔽或网络极度恶劣,少数节点可能需要手动干预。\n\n**是否确定挂载并执行 OTA 指令?**"
|
||||||
|
send_ui "$CHAT_ID" "$WARNING_MSG" "$CONFIRM_BTNS"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"all_ota_execute")
|
||||||
|
NODE_DATA=$(db_exec "SELECT node_name, agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID' AND enable_ota='true';")
|
||||||
|
if [ -z "$NODE_DATA" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⚠️ 您名下暂无开启 OTA 权限的在线节点。"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒全舰队执行 OTA 升级...**%0A*(节点升级成功后会主动发回新的入库确认,请注意查收)*"
|
||||||
|
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
|
||||||
|
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_ota")
|
||||||
|
curl -k -s -m 5 "$TARGET_URL" > /dev/null &
|
||||||
|
sleep 0.3 # 严格流量削峰
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"master_ota_confirm")
|
||||||
|
CONFIRM_BTNS="[[{\"text\":\"🚨 确认重构司令部\",\"callback_data\":\"master_ota_execute\"}], [{\"text\":\"取消操作\",\"callback_data\":\"/start\"}]]"
|
||||||
|
WARNING_MSG="☢️ **【最高指令:中枢金蝉脱壳】**\n\n此操作将拉取最新源码并强行覆盖司令部核心进程。\n\n⚠️ **风险提示**:\n升级期间司令部将短暂失联(约3-5秒)。完成后会自动发送捷报。\n\n**是否确定执行司令部自我升级?**"
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_ui "$CHAT_ID" "$MSG_ID" "$WARNING_MSG" "$CONFIRM_BTNS"
|
||||||
|
else
|
||||||
|
send_ui "$CHAT_ID" "$WARNING_MSG" "$CONFIRM_BTNS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"master_ota_execute")
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在下载重构图纸,司令部即将进入静默重启..."
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "⏳ 正在下载重构图纸,司令部即将进入静默重启..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 下载最新的 master install 脚本作为幽灵进程
|
||||||
|
curl -fsSL "${REPO_RAW_URL}/master/install_master.sh" -o "/tmp/install_master.sh"
|
||||||
|
|
||||||
|
# [v3.6.3 修复] 🚀 OTA 防砖机制:严格校验脚本完整性
|
||||||
|
if ! bash -n "/tmp/install_master.sh" >/dev/null 2>&1; then
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_msg "$CHAT_ID" "$MSG_ID" "❌ OTA 传输受损:脚本下载不完整,已触发防砖熔断,升级取消!"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "❌ OTA 传输受损:脚本下载不完整,已触发防砖熔断,升级取消!"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "/tmp/install_master.sh"
|
||||||
|
|
||||||
|
# 抛出幽灵进程进行脱壳升级,传递静默变量与回执 ID
|
||||||
|
# [修复] 必须显式将环境变量注入到 bash -c 的指令串中,防止被 systemd-run 沙盒隔离丢弃
|
||||||
|
if command -v systemd-run >/dev/null 2>&1; then
|
||||||
|
systemd-run --quiet --no-block /bin/bash -c "export SILENT_MASTER_OTA='true'; export OTA_CHAT_ID='$CHAT_ID'; bash /tmp/install_master.sh"
|
||||||
|
else
|
||||||
|
export SILENT_MASTER_OTA="true"
|
||||||
|
export OTA_CHAT_ID="$CHAT_ID"
|
||||||
|
nohup bash /tmp/install_master.sh >/dev/null 2>&1 & disown
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 当前旧进程休眠并等待被幽灵进程处决
|
||||||
|
sleep 10
|
||||||
;;
|
;;
|
||||||
|
|
||||||
"all_reports")
|
"all_reports")
|
||||||
@@ -169,11 +372,13 @@ while true; do
|
|||||||
if [ -z "$NODE_DATA" ]; then
|
if [ -z "$NODE_DATA" ]; then
|
||||||
send_msg "$CHAT_ID" "⚠️ 您名下暂无在线节点。"
|
send_msg "$CHAT_ID" "⚠️ 您名下暂无在线节点。"
|
||||||
else
|
else
|
||||||
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在召唤所有哨兵回传简报...**"
|
# [文案优化] 提前告知指挥官需要排队等待
|
||||||
|
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在召唤所有哨兵回传简报...**%0A*(为防止触发 TG 官方限流,简报将排队依次送达,请耐心等待)*"
|
||||||
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
|
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
|
||||||
# 🛡️ [v3.0.4] 动态签名防重放批量下发
|
|
||||||
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_report")
|
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_report")
|
||||||
curl -s -m 5 "$TARGET_URL" > /dev/null &
|
curl -k -s -m 5 "$TARGET_URL" > /dev/null &
|
||||||
|
# [致命修复] 强行休眠 2 秒!错开 TG 官方 1条/秒 的发信红线
|
||||||
|
sleep 2
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -186,14 +391,96 @@ while true; do
|
|||||||
else
|
else
|
||||||
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒所有哨兵执行系统维护...**"
|
send_msg "$CHAT_ID" "📢 **司令部指令下达:正在唤醒所有哨兵执行系统维护...**"
|
||||||
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
|
echo "$NODE_DATA" | while IFS='|' read -r NNAME AIP APORT; do
|
||||||
# 🛡️ [v3.0.4] 动态签名防重放批量下发 (维护模块)
|
|
||||||
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_run")
|
TARGET_URL=$(generate_signed_url "$AIP" "$APORT" "/trigger_run")
|
||||||
curl -s -m 5 "$TARGET_URL" > /dev/null &
|
curl -k -s -m 5 "$TARGET_URL" > /dev/null &
|
||||||
|
sleep 0.2 # [新增] 流量削峰:防止瞬间 fork 导致句柄耗尽
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
# ====================================================================
|
# ====================================================================
|
||||||
|
|
||||||
|
# ------------------- 🚨 请将下面这段代码插入在这里 -------------------
|
||||||
|
|
||||||
|
# ================== [v4.0.0 新增: 文本指令直接控制通道] ==================
|
||||||
|
"/quality"|"/quality@"*)
|
||||||
|
TARGET_NODE=$(echo "$TEXT" | awk '{print $2}')
|
||||||
|
if [ -z "$TARGET_NODE" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⚠️ 请指定目标节点。例如: \`/quality HK-1\`%0A或通过雷达面板进行选择操作。"
|
||||||
|
else
|
||||||
|
TARGET_NODE=$(echo "$TARGET_NODE" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
# [加密通讯逻辑]
|
||||||
|
AGENT_INFO=$(db_exec "SELECT agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1)
|
||||||
|
AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2)
|
||||||
|
|
||||||
|
if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` ($AGENT_IP) 下发 [quality] 指令,请稍候..."
|
||||||
|
|
||||||
|
# 动态 HMAC 签名防篡改
|
||||||
|
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_quality")
|
||||||
|
RESPONSE=$(curl -k -s -m 5 "$TARGET_URL" || echo "FAILED")
|
||||||
|
|
||||||
|
# 结果判定
|
||||||
|
if [ "$RESPONSE" == "FAILED" ]; then
|
||||||
|
send_msg "$CHAT_ID" "❌ 指令下发超时或失败!请检查节点公网 IP 或防火墙端口 ($AGENT_PORT) 是否放行。"
|
||||||
|
elif [[ "$RESPONSE" == *"403"* ]]; then
|
||||||
|
send_msg "$CHAT_ID" "⚠️ **拒绝执行**:该节点未在本地开启此模块,请检查安装时的配置!"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "✅ 节点 \`$TARGET_NODE\` 回应: 🔍 深海声呐已投放!请等待异步战报回传。"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "❌ 数据库中未找到该节点的通讯地址。"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"/trend"|"/trend@"*)
|
||||||
|
TARGET_NODE=$(echo "$TEXT" | awk '{print $2}')
|
||||||
|
if [ -z "$TARGET_NODE" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⚠️ 请指定目标节点。例如: \`/trend HK-1\`%0A或通过雷达面板进行选择操作。"
|
||||||
|
else
|
||||||
|
TARGET_NODE=$(echo "$TARGET_NODE" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
TREND_DATA=$(db_exec "SELECT datetime(check_time, 'localtime'), scam_score, goog_status, nf_status, gpt_status FROM ip_trend_log WHERE node_name='$TARGET_NODE' ORDER BY check_time DESC LIMIT 15;")
|
||||||
|
|
||||||
|
if [ -z "$TREND_DATA" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⚠️ 节点 \`$TARGET_NODE\` 暂无历史体检档案。请先执行 /quality 投放声呐进行探测。"
|
||||||
|
else
|
||||||
|
TARGET_ALIAS=$(db_exec "SELECT IFNULL(node_alias, node_name) FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
[ -z "$TARGET_ALIAS" ] && TARGET_ALIAS="$TARGET_NODE"
|
||||||
|
|
||||||
|
TEXT_RES="📈 *[${TARGET_ALIAS}] 历史态势感知 (近15次)*\n\n"
|
||||||
|
TEXT_RES+="时间(本地) | 风险 | 谷歌 | NF | GPT\n"
|
||||||
|
TEXT_RES+="-----------------------------------------\n"
|
||||||
|
|
||||||
|
while IFS='|' read -r c_time score goog nf gpt; do
|
||||||
|
[ -z "$score" ] && score="0"
|
||||||
|
[ -z "$goog" ] && goog="未知"
|
||||||
|
[ -z "$nf" ] && nf="未知"
|
||||||
|
[ -z "$gpt" ] && gpt="未知"
|
||||||
|
|
||||||
|
short_time=$(echo "$c_time" | cut -c 6-16)
|
||||||
|
|
||||||
|
if [ "$score" -le 20 ]; then SCORE_EMJ="🟢"
|
||||||
|
elif [ "$score" -le 60 ]; then SCORE_EMJ="🟡"
|
||||||
|
else SCORE_EMJ="🔴"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TEXT_RES+="\`${short_time}\` | ${SCORE_EMJ}\`${score}\` | \`${goog}\` | \`${nf}\` | \`${gpt}\`\n"
|
||||||
|
done <<< "$TREND_DATA"
|
||||||
|
TEXT_RES+="\n_💡 提示:🔴风险分 >60 极易触发网页验证码拦截;谷歌显示 CN 即为高危送中。_"
|
||||||
|
|
||||||
|
# [v4.0.3 体验升级] 注入交互式控制台按钮
|
||||||
|
BTNS="[[{\"text\":\"⚙️ 调出该节点控制台\",\"callback_data\":\"manage:$TARGET_NODE\"}]]"
|
||||||
|
send_ui "$CHAT_ID" "$TEXT_RES" "$BTNS"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
# ------------------- 🚨 插入代码到此结束 -------------------
|
||||||
|
|
||||||
"list_nodes")
|
"list_nodes")
|
||||||
# 【V3.1.3】一级菜单:大区聚合并列出数量
|
# 【V3.1.3】一级菜单:大区聚合并列出数量
|
||||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||||
@@ -203,16 +490,12 @@ while true; do
|
|||||||
BTNS="["
|
BTNS="["
|
||||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||||
FLAG="🌐"
|
FLAG=$(get_flag "$REGION_NAME")
|
||||||
case "$REGION_NAME" in
|
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||||
"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"
|
done <<< "$REGION_DATA"
|
||||||
BTNS="${BTNS%,}]"
|
# L1 追加返回中枢逃生舱
|
||||||
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n请选择要检阅的战区:" "$BTNS"
|
BTNS="$BTNS[{\"text\":\"🏠 回到司令部\",\"callback_data\":\"/start\"}]]"
|
||||||
|
send_ui "$CHAT_ID" "🌍 **全视界战略雷达**\n已为您聚合当前舰队的部署大区,请选择要检阅的战区:" "$BTNS"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@@ -221,15 +504,17 @@ while true; do
|
|||||||
TARGET_REGION=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9')
|
TARGET_REGION=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9')
|
||||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
NODE_LIST=$(db_exec "SELECT node_name FROM nodes WHERE chat_id='$CHAT_ID' AND region='$TARGET_REGION';")
|
# [v3.5.2] 提取物理主键和展示别名
|
||||||
|
NODE_LIST=$(db_exec "SELECT node_name, IFNULL(node_alias, node_name) FROM nodes WHERE chat_id='$CHAT_ID' AND region='$TARGET_REGION';")
|
||||||
if [ -z "$NODE_LIST" ]; then
|
if [ -z "$NODE_LIST" ]; then
|
||||||
send_msg "$CHAT_ID" "⚠️ 该战区下暂无可用节点。"
|
send_msg "$CHAT_ID" "⚠️ 该战区下暂无可用节点。"
|
||||||
else
|
else
|
||||||
BTNS="["
|
BTNS="["
|
||||||
COL=0
|
COL=0
|
||||||
ROW_STR="["
|
ROW_STR="["
|
||||||
for N in $NODE_LIST; do
|
while IFS='|' read -r N_NAME N_ALIAS; do
|
||||||
ROW_STR="$ROW_STR{\"text\":\"🖥️ $N\",\"callback_data\":\"manage:$N\"},"
|
[ -z "$N_NAME" ] && continue
|
||||||
|
ROW_STR="$ROW_STR{\"text\":\"🖥️ $N_ALIAS\",\"callback_data\":\"manage:$N_NAME\"},"
|
||||||
COL=$((COL+1))
|
COL=$((COL+1))
|
||||||
if [ $COL -eq 2 ]; then
|
if [ $COL -eq 2 ]; then
|
||||||
ROW_STR="${ROW_STR%,}]"
|
ROW_STR="${ROW_STR%,}]"
|
||||||
@@ -237,24 +522,119 @@ while true; do
|
|||||||
COL=0
|
COL=0
|
||||||
ROW_STR="["
|
ROW_STR="["
|
||||||
fi
|
fi
|
||||||
done
|
done <<< "$NODE_LIST"
|
||||||
# 如果是奇数,补齐最后的尾巴
|
# 如果是奇数,补齐最后的尾巴
|
||||||
if [ $COL -eq 1 ]; then
|
if [ $COL -eq 1 ]; then
|
||||||
ROW_STR="${ROW_STR%,}]"
|
ROW_STR="${ROW_STR%,}]"
|
||||||
BTNS="$BTNS$ROW_STR,"
|
BTNS="$BTNS$ROW_STR,"
|
||||||
fi
|
fi
|
||||||
# 添加返回上级大区雷达的按钮
|
# L2 追加双重逃生舱
|
||||||
BTNS="$BTNS[{\"text\":\"⬅️ 返回全球战区分布\",\"callback_data\":\"list_nodes\"}]]"
|
BTNS="$BTNS[{\"text\":\"⬅️ 返回战区地图\",\"callback_data\":\"list_nodes\"}, {\"text\":\"🏠 回到司令部\",\"callback_data\":\"/start\"}]]"
|
||||||
send_ui "$CHAT_ID" "📍 **[$TARGET_REGION] 战区哨兵矩阵**\n请下达控制指令:" "$BTNS"
|
send_ui "$CHAT_ID" "📍 **[$TARGET_REGION] 战区哨兵矩阵**\n请锁定要执行战术动作的具体目标:" "$BTNS"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
manage:*)
|
manage:*)
|
||||||
# 🛡️ 强制过滤节点名,防止面板渲染时发生 XSS 或注入
|
|
||||||
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
# 【核心升级】拆分下发按钮,精准对应 Google 与 Trust 两个模块,并排版为 3 行 2 列
|
TARGET_ALIAS=$(db_exec "SELECT IFNULL(node_alias, node_name) FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
BTNS="[[{\"text\":\"📍 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 信用净化\",\"callback_data\":\"trust:$TARGET_NODE\"}], [{\"text\":\"📜 实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}, {\"text\":\"📊 统计战报\",\"callback_data\":\"report:$TARGET_NODE\"}], [{\"text\":\"🗑️ 剔除失联节点\",\"callback_data\":\"del:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回大区目录\",\"callback_data\":\"list_nodes\"}]]"
|
[ -z "$TARGET_ALIAS" ] && TARGET_ALIAS="$TARGET_NODE"
|
||||||
send_ui "$CHAT_ID" "⚙️ **目标锁定**: \`$TARGET_NODE\`\n请选择战术动作:" "$BTNS"
|
|
||||||
|
# 抓取节点全景元数据
|
||||||
|
TOGGLE_INFO=$(db_exec "SELECT enable_google, enable_trust, enable_ota, agent_ip, IFNULL(last_seen, '未知') FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
ST_GOOGLE=$(echo "$TOGGLE_INFO" | cut -d'|' -f1)
|
||||||
|
ST_TRUST=$(echo "$TOGGLE_INFO" | cut -d'|' -f2)
|
||||||
|
ST_OTA=$(echo "$TOGGLE_INFO" | cut -d'|' -f3)
|
||||||
|
A_IP=$(echo "$TOGGLE_INFO" | cut -d'|' -f4)
|
||||||
|
LAST_SEEN=$(echo "$TOGGLE_INFO" | cut -d'|' -f5)
|
||||||
|
|
||||||
|
# 动态渲染状态文字
|
||||||
|
[ "$ST_GOOGLE" == "true" ] && BTN_G="🟢 Google巡逻: 已开" && ACT_G="false" || { BTN_G="🔴 Google巡逻: 已停"; ACT_G="true"; }
|
||||||
|
[ "$ST_TRUST" == "true" ] && BTN_T="🟢 信用净化: 已开" && ACT_T="false" || { BTN_T="🔴 信用净化: 已停"; ACT_T="true"; }
|
||||||
|
|
||||||
|
# 模块一:即时战术动作 (V4.0.0 引入深海声呐与趋势面板)
|
||||||
|
BTN_ACTION="[{\"text\":\"📍 触发 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 触发信用净化\",\"callback_data\":\"trust:$TARGET_NODE\"}], [{\"text\":\"🔍 投放深海声呐 (查IP质量)\",\"callback_data\":\"quality:$TARGET_NODE\"}, {\"text\":\"📈 查看 IP 污染趋势图\",\"callback_data\":\"trend:$TARGET_NODE\"}], [{\"text\":\"📜 提取终端实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}, {\"text\":\"📊 生成单机战报\",\"callback_data\":\"report:$TARGET_NODE\"}]"
|
||||||
|
|
||||||
|
# 模块二:养护状态启停
|
||||||
|
BTN_TOGGLE="[{\"text\":\"$BTN_G\",\"callback_data\":\"toggle:google:$TARGET_NODE:$ACT_G\"}, {\"text\":\"$BTN_T\",\"callback_data\":\"toggle:trust:$TARGET_NODE:$ACT_T\"}]"
|
||||||
|
|
||||||
|
# 模块三:深度配置管理 (结合 UI 熔断)
|
||||||
|
if [ "$IS_OFFICIAL_GATEWAY" != "true" ] && [ "$ST_OTA" == "true" ]; then
|
||||||
|
BTN_CONFIG="[{\"text\":\"✏️ 更改终端展示代号\",\"callback_data\":\"rename:$TARGET_NODE\"}, {\"text\":\"🆙 OTA 静默升级\",\"callback_data\":\"ota_confirm:$TARGET_NODE\"}]"
|
||||||
|
else
|
||||||
|
BTN_CONFIG="[{\"text\":\"✏️ 更改终端展示代号\",\"callback_data\":\"rename:$TARGET_NODE\"}]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 模块四:危险区与逃生舱
|
||||||
|
BTN_DANGER="[{\"text\":\"🗑️ 从中枢销毁该档案\",\"callback_data\":\"del:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回战区列表\",\"callback_data\":\"list_nodes\"}]"
|
||||||
|
|
||||||
|
# 组合终极矩阵
|
||||||
|
BTNS="[$BTN_ACTION, $BTN_TOGGLE, $BTN_CONFIG, $BTN_DANGER]"
|
||||||
|
|
||||||
|
TEXT_MSG="⚙️ **目标锁定**: \`$TARGET_ALIAS\`\n(底层标识: \`$TARGET_NODE\`)\n🌐 IP 坐标: \`$A_IP\`\n🕒 最后通讯: \`$LAST_SEEN\`\n\n请下达精确控制指令:"
|
||||||
|
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_ui "$CHAT_ID" "$MSG_ID" "$TEXT_MSG" "$BTNS"
|
||||||
|
else
|
||||||
|
send_ui "$CHAT_ID" "$TEXT_MSG" "$BTNS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
toggle:*)
|
||||||
|
# [动态启停通信闭环]
|
||||||
|
IFS=':' read -r CMD MOD_NAME TARGET_NODE TARGET_STATE <<< "$TEXT"
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
AGENT_INFO=$(db_exec "SELECT agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1)
|
||||||
|
AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2)
|
||||||
|
|
||||||
|
if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then
|
||||||
|
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_toggle")
|
||||||
|
TARGET_URL="${TARGET_URL}&mod=${MOD_NAME}&state=${TARGET_STATE}"
|
||||||
|
|
||||||
|
RESPONSE=$(curl -k -s -m 5 "$TARGET_URL" || echo "FAILED")
|
||||||
|
|
||||||
|
if [[ "$RESPONSE" == *"Action Accepted"* ]]; then
|
||||||
|
# 下发成功,更新 DB,原位重绘
|
||||||
|
db_exec "UPDATE nodes SET enable_${MOD_NAME}='$TARGET_STATE' WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';"
|
||||||
|
|
||||||
|
TOGGLE_INFO=$(db_exec "SELECT enable_google, enable_trust FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
ST_GOOGLE=$(echo "$TOGGLE_INFO" | cut -d'|' -f1)
|
||||||
|
ST_TRUST=$(echo "$TOGGLE_INFO" | cut -d'|' -f2)
|
||||||
|
[ "$ST_GOOGLE" == "true" ] && BTN_G="🔴 停用 Google 纠偏" && ACT_G="false" || { BTN_G="🟢 启用 Google 纠偏"; ACT_G="true"; }
|
||||||
|
[ "$ST_TRUST" == "true" ] && BTN_T="🔴 停用信用净化" && ACT_T="false" || { BTN_T="🟢 启用信用净化"; ACT_T="true"; }
|
||||||
|
|
||||||
|
# 切换后直接复用扁平化 L3 面板的重绘逻辑
|
||||||
|
TOGGLE_INFO=$(db_exec "SELECT enable_google, enable_trust, enable_ota, agent_ip, IFNULL(last_seen, '未知') FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
ST_GOOGLE=$(echo "$TOGGLE_INFO" | cut -d'|' -f1)
|
||||||
|
ST_TRUST=$(echo "$TOGGLE_INFO" | cut -d'|' -f2)
|
||||||
|
ST_OTA=$(echo "$TOGGLE_INFO" | cut -d'|' -f3)
|
||||||
|
A_IP=$(echo "$TOGGLE_INFO" | cut -d'|' -f4)
|
||||||
|
LAST_SEEN=$(echo "$TOGGLE_INFO" | cut -d'|' -f5)
|
||||||
|
|
||||||
|
[ "$ST_GOOGLE" == "true" ] && BTN_G="🟢 Google巡逻: 已开" && ACT_G="false" || { BTN_G="🔴 Google巡逻: 已停"; ACT_G="true"; }
|
||||||
|
[ "$ST_TRUST" == "true" ] && BTN_T="🟢 信用净化: 已开" && ACT_T="false" || { BTN_T="🔴 信用净化: 已停"; ACT_T="true"; }
|
||||||
|
|
||||||
|
# 模块一:即时战术动作 (V4.0.0 引入深海声呐与趋势面板)
|
||||||
|
BTN_ACTION="[{\"text\":\"📍 触发 Google 纠偏\",\"callback_data\":\"google:$TARGET_NODE\"}, {\"text\":\"🛡️ 触发信用净化\",\"callback_data\":\"trust:$TARGET_NODE\"}], [{\"text\":\"🔍 投放深海声呐 (查IP质量)\",\"callback_data\":\"quality:$TARGET_NODE\"}, {\"text\":\"📈 查看 IP 污染趋势图\",\"callback_data\":\"trend:$TARGET_NODE\"}], [{\"text\":\"📜 提取终端实时日志\",\"callback_data\":\"log:$TARGET_NODE\"}, {\"text\":\"📊 生成单机战报\",\"callback_data\":\"report:$TARGET_NODE\"}]"
|
||||||
|
BTN_TOGGLE="[{\"text\":\"$BTN_G\",\"callback_data\":\"toggle:google:$TARGET_NODE:$ACT_G\"}, {\"text\":\"$BTN_T\",\"callback_data\":\"toggle:trust:$TARGET_NODE:$ACT_T\"}]"
|
||||||
|
|
||||||
|
if [ "$IS_OFFICIAL_GATEWAY" != "true" ] && [ "$ST_OTA" == "true" ]; then
|
||||||
|
BTN_CONFIG="[{\"text\":\"✏️ 更改终端展示代号\",\"callback_data\":\"rename:$TARGET_NODE\"}, {\"text\":\"🆙 OTA 静默升级\",\"callback_data\":\"ota_confirm:$TARGET_NODE\"}]"
|
||||||
|
else
|
||||||
|
BTN_CONFIG="[{\"text\":\"✏️ 更改终端展示代号\",\"callback_data\":\"rename:$TARGET_NODE\"}]"
|
||||||
|
fi
|
||||||
|
BTN_DANGER="[{\"text\":\"🗑️ 从中枢销毁该档案\",\"callback_data\":\"del:$TARGET_NODE\"}, {\"text\":\"⬅️ 返回战区列表\",\"callback_data\":\"list_nodes\"}]"
|
||||||
|
|
||||||
|
BTNS="[$BTN_ACTION, $BTN_TOGGLE, $BTN_CONFIG, $BTN_DANGER]"
|
||||||
|
TARGET_ALIAS=$(db_exec "SELECT IFNULL(node_alias, node_name) FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
|
||||||
|
TEXT_MSG="⚙️ **目标锁定**: \`$TARGET_ALIAS\`\n(底层标识: \`$TARGET_NODE\`)\n🌐 IP 坐标: \`$A_IP\`\n🕒 最后通讯: \`$LAST_SEEN\`\n\n✅ **执行成功**: 模块 [$MOD_NAME] 状态已切换为 $TARGET_STATE!"
|
||||||
|
edit_ui "$CHAT_ID" "$MSG_ID" "$TEXT_MSG" "$BTNS"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "❌ 指令下发失败,安全策略禁止降级重试。"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
del:*)
|
del:*)
|
||||||
@@ -262,8 +642,19 @@ while true; do
|
|||||||
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
db_exec "DELETE FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';"
|
# 🛡️ [终极防线: 防越权横向打击] 先校验该节点是否真实属于当前操作者!
|
||||||
send_msg "$CHAT_ID" "🗑️ 节点 \`$TARGET_NODE\` 的档案已从司令部彻底销毁!"
|
# 因为趋势库中没有 Chat_ID 标识,不校验直接删会给黑客伪造回调清空他人数据的机会!
|
||||||
|
VALID_OWNER=$(db_exec "SELECT 1 FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
|
||||||
|
if [ "$VALID_OWNER" == "1" ]; then
|
||||||
|
# 验权通过,执行原子化级联销毁:同时抹除主配置与历史污染趋势
|
||||||
|
db_exec "DELETE FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';"
|
||||||
|
db_exec "DELETE FROM ip_trend_log WHERE node_name='$TARGET_NODE';"
|
||||||
|
send_msg "$CHAT_ID" "🗑️ 节点 \`$TARGET_NODE\` 的档案及历史污染趋势已从司令部彻底销毁!"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "⛔ **安全拦截**:销毁失败。目标节点不存在或您无权越权操作!"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
# 剔除后直接返回上级一级雷达菜单
|
# 剔除后直接返回上级一级雷达菜单
|
||||||
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
REGION_DATA=$(db_exec "SELECT region, COUNT(*) FROM nodes WHERE chat_id='$CHAT_ID' GROUP BY region;")
|
||||||
@@ -273,11 +664,7 @@ while true; do
|
|||||||
BTNS="["
|
BTNS="["
|
||||||
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
while IFS='|' read -r REGION_NAME NODE_COUNT; do
|
||||||
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
[ -z "$REGION_NAME" ] && REGION_NAME="UNKNOWN"
|
||||||
FLAG="🌐"
|
FLAG=$(get_flag "$REGION_NAME")
|
||||||
case "$REGION_NAME" in
|
|
||||||
"US") FLAG="🇺🇸" ;; "JP") FLAG="🇯🇵" ;; "HK") FLAG="🇭🇰" ;;
|
|
||||||
"SG") FLAG="🇸🇬" ;; "UK"|"GB") FLAG="🇬🇧" ;; "DE") FLAG="🇩🇪" ;; "FR") FLAG="🇫🇷" ;;
|
|
||||||
esac
|
|
||||||
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
BTNS="$BTNS[{\"text\":\"$FLAG $REGION_NAME ($NODE_COUNT 台)\",\"callback_data\":\"region:$REGION_NAME\"}],"
|
||||||
done <<< "$REGION_DATA"
|
done <<< "$REGION_DATA"
|
||||||
BTNS="${BTNS%,}]"
|
BTNS="${BTNS%,}]"
|
||||||
@@ -285,10 +672,97 @@ while true; do
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
# 【核心升级】增加拦截规则,支持 google 和 trust 前缀
|
rename:*)
|
||||||
google:*|trust:*|run:*|report:*|log:*)
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
# [v3.5.2] 发送 ForceReply 引导用户回复
|
||||||
|
curl -s -X POST "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"chat_id\":\"$CHAT_ID\",\"text\":\"✏️ 请回复本消息以重命名节点:\n\`$TARGET_NODE\`\n(仅限中英文、数字,最长20字符)\",\"parse_mode\":\"Markdown\",\"reply_markup\":{\"force_reply\":true}}" > /dev/null
|
||||||
|
;;
|
||||||
|
|
||||||
|
do_rename:*)
|
||||||
|
# [v3.5.2] 内部重命名路由 (已被第2处的代码拦截并格式化)
|
||||||
|
IFS=':' read -r CMD TARGET_NODE NEW_ALIAS <<< "$TEXT"
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
AGENT_INFO=$(db_exec "SELECT agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1)
|
||||||
|
AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2)
|
||||||
|
|
||||||
|
if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then
|
||||||
|
send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` 下发重命名指令,正在建立加密隧道..."
|
||||||
|
|
||||||
|
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_rename")
|
||||||
|
|
||||||
|
# [绝密防线: Base64 编码绕过一切传输限制与 WAF 拦截]
|
||||||
|
ALIAS_B64=$(echo -n "$NEW_ALIAS" | base64 | tr -d '\n' | tr '+/' '-_')
|
||||||
|
TARGET_URL="${TARGET_URL}&b64=${ALIAS_B64}"
|
||||||
|
|
||||||
|
RESPONSE=$(curl -k -s -m 5 "$TARGET_URL" || echo "FAILED")
|
||||||
|
|
||||||
|
if [ "$RESPONSE" == "FAILED" ]; then
|
||||||
|
send_msg "$CHAT_ID" "❌ 指令下发超时!为防范劫持风险,已终止请求。"
|
||||||
|
elif [[ "$RESPONSE" == *"Action Accepted"* ]]; then
|
||||||
|
# [v3.5.2 极致丝滑] 确认 Agent 修改成功后,Master 立即自动同步本地 SQLite 数据库!
|
||||||
|
db_exec "UPDATE nodes SET node_alias='$NEW_ALIAS' WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE';"
|
||||||
|
send_msg "$CHAT_ID" "✅ 通讯成功!节点别名已下发: \`$NEW_ALIAS\`%0A*(司令部档案已自动刷新,雷达面板已同步)*"
|
||||||
|
else
|
||||||
|
# 增加输出 RESPONSE 调试信息,排查任何拦截死因
|
||||||
|
send_msg "$CHAT_ID" "⚠️ 节点拒绝了请求,请确保 Agent 已更新至 v3.5.2%0A(回传信息: \`${RESPONSE}\`)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "❌ 数据库中未找到该节点的通讯地址。"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
ota_confirm:*)
|
||||||
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
# 将取消动作引导回 manage,因为 adv 已经被删除了
|
||||||
|
CONFIRM_BTNS="[[{\"text\":\"🚨 确认执行远程升级\",\"callback_data\":\"ota_execute:$TARGET_NODE\"}], [{\"text\":\"取消\",\"callback_data\":\"manage:$TARGET_NODE\"}]]"
|
||||||
|
send_ui "$CHAT_ID" "☢️ **操作确认**:即将向 \`$TARGET_NODE\` 下发 OTA 热更新指令。\n节点更新完成后会自动发送包含新版本号的注册回执,确定执行?" "$CONFIRM_BTNS"
|
||||||
|
;;
|
||||||
|
|
||||||
|
ota_execute:*)
|
||||||
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
AGENT_INFO=$(db_exec "SELECT agent_ip, agent_port FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
AGENT_IP=$(echo "$AGENT_INFO" | cut -d'|' -f1)
|
||||||
|
AGENT_PORT=$(echo "$AGENT_INFO" | cut -d'|' -f2)
|
||||||
|
|
||||||
|
if [ -n "$AGENT_IP" ] && [ -n "$AGENT_PORT" ]; then
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_msg "$CHAT_ID" "$MSG_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..."
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "⏳ 正在向 \`$TARGET_NODE\` 发送 OTA 触发报文..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_ota")
|
||||||
|
RESPONSE=$(curl -k -s -m 5 "$TARGET_URL" || echo "FAILED")
|
||||||
|
|
||||||
|
if [ "$RESPONSE" == "FAILED" ]; then
|
||||||
|
TEXT_RES="❌ OTA 指令下发彻底失败!链路异常或严禁使用 HTTP 降级通讯。"
|
||||||
|
elif [[ "$RESPONSE" == *"403"* ]]; then
|
||||||
|
TEXT_RES="⚠️ **节点拒绝执行**:该节点本地未开启 OTA 权限或运行在官方网关下!"
|
||||||
|
else
|
||||||
|
TEXT_RES="✅ OTA (TLS加密) 触发成功!节点正在后台执行拉取重构..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_msg "$CHAT_ID" "$MSG_ID" "$TEXT_RES"
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "$TEXT_RES"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
send_msg "$CHAT_ID" "❌ 数据库中未找到该节点的通讯地址。"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 【核心升级 v4.0.0】增加拦截规则,支持 quality 前缀
|
||||||
|
google:*|trust:*|run:*|report:*|log:*|quality:*)
|
||||||
# 🛡️ 提取并强制过滤动作参数、节点名与 CHAT_ID
|
# 🛡️ 提取并强制过滤动作参数、节点名与 CHAT_ID
|
||||||
ACTION_TYPE=$(echo "$TEXT" | cut -d':' -f1 | tr -cd 'a-z')
|
ACTION_TYPE=$(echo "$TEXT" | cut -d':' -f1)
|
||||||
TARGET_NODE=$(echo "$TEXT" | cut -d':' -f2 | tr -cd 'a-zA-Z0-9_.-')
|
TARGET_NODE=$(echo "$TEXT" | cut -d':' -f2 | tr -cd 'a-zA-Z0-9_.-')
|
||||||
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
@@ -306,11 +780,11 @@ while true; do
|
|||||||
|
|
||||||
# 🛡️ [v3.0.4] 动态签名生成与触发 (防重放与防篡改)
|
# 🛡️ [v3.0.4] 动态签名生成与触发 (防重放与防篡改)
|
||||||
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_${ACTION_TYPE}")
|
TARGET_URL=$(generate_signed_url "$AGENT_IP" "$AGENT_PORT" "/trigger_${ACTION_TYPE}")
|
||||||
RESPONSE=$(curl -s -m 5 "$TARGET_URL" || echo "FAILED")
|
RESPONSE=$(curl -k -s -m 5 "$TARGET_URL" || echo "FAILED")
|
||||||
|
|
||||||
# 结果判定
|
# 结果判定
|
||||||
if [ "$RESPONSE" == "FAILED" ]; then
|
if [ "$RESPONSE" == "FAILED" ]; then
|
||||||
TEXT_RES="❌ 指令下发超时或失败!请检查节点公网 IP 或防火墙端口 ($AGENT_PORT) 是否放行。"
|
TEXT_RES="❌ 指令下发超时或失败!为保护链路安全,已终止通信 (严禁降级为 HTTP)。"
|
||||||
elif [[ "$RESPONSE" == *"403"* ]]; then
|
elif [[ "$RESPONSE" == *"403"* ]]; then
|
||||||
TEXT_RES="⚠️ **拒绝执行**:该节点未在本地开启此模块,请检查安装时的配置!"
|
TEXT_RES="⚠️ **拒绝执行**:该节点未在本地开启此模块,请检查安装时的配置!"
|
||||||
else
|
else
|
||||||
@@ -318,6 +792,8 @@ while true; do
|
|||||||
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 回应: 📍 Google 纠偏程序启动。"
|
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 回应: 📍 Google 纠偏程序启动。"
|
||||||
elif [ "$ACTION_TYPE" == "trust" ]; then
|
elif [ "$ACTION_TYPE" == "trust" ]; then
|
||||||
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 回应: 🛡️ IP 信用净化程序启动。"
|
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 回应: 🛡️ IP 信用净化程序启动。"
|
||||||
|
elif [ "$ACTION_TYPE" == "quality" ]; then
|
||||||
|
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 回应: 🔍 深海声呐已投放!请等待异步战报回传。"
|
||||||
elif [ "$ACTION_TYPE" == "log" ]; then
|
elif [ "$ACTION_TYPE" == "log" ]; then
|
||||||
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 正在抓取日志..."
|
TEXT_RES="✅ 节点 \`$TARGET_NODE\` 正在抓取日志..."
|
||||||
else
|
else
|
||||||
@@ -335,6 +811,55 @@ while true; do
|
|||||||
send_msg "$CHAT_ID" "❌ 数据库中未找到该节点的通讯地址。"
|
send_msg "$CHAT_ID" "❌ 数据库中未找到该节点的通讯地址。"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
trend:*)
|
||||||
|
# [v4.0.2 优化: 扩容 15 次追踪并引入 GOOG/GPT 状态]
|
||||||
|
TARGET_NODE=$(echo "${TEXT#*:}" | tr -cd 'a-zA-Z0-9_.-')
|
||||||
|
CHAT_ID=$(echo "$CHAT_ID" | tr -cd '0-9-')
|
||||||
|
|
||||||
|
TREND_DATA=$(db_exec "SELECT datetime(check_time, 'localtime'), scam_score, goog_status, nf_status, gpt_status FROM ip_trend_log WHERE node_name='$TARGET_NODE' ORDER BY check_time DESC LIMIT 15;")
|
||||||
|
|
||||||
|
if [ -z "$TREND_DATA" ]; then
|
||||||
|
TEXT_RES="⚠️ 节点 \`$TARGET_NODE\` 暂无历史体检档案。请先执行 [🔍 投放深海声呐] 进行探测。"
|
||||||
|
else
|
||||||
|
TARGET_ALIAS=$(db_exec "SELECT IFNULL(node_alias, node_name) FROM nodes WHERE chat_id='$CHAT_ID' AND node_name='$TARGET_NODE' LIMIT 1;")
|
||||||
|
[ -z "$TARGET_ALIAS" ] && TARGET_ALIAS="$TARGET_NODE"
|
||||||
|
|
||||||
|
TEXT_RES="📈 *[${TARGET_ALIAS}] 历史态势感知 (近15次)*\n\n"
|
||||||
|
TEXT_RES+="时间(本地) | 风险 | 谷歌 | NF | GPT\n"
|
||||||
|
TEXT_RES+="-----------------------------------------\n"
|
||||||
|
|
||||||
|
while IFS='|' read -r c_time score goog nf gpt; do
|
||||||
|
[ -z "$score" ] && score="0"
|
||||||
|
[ -z "$goog" ] && goog="未知"
|
||||||
|
[ -z "$nf" ] && nf="未知"
|
||||||
|
[ -z "$gpt" ] && gpt="未知"
|
||||||
|
|
||||||
|
# 时间做极简切割 (截取 04-24 20:52) 节省横向空间
|
||||||
|
short_time=$(echo "$c_time" | cut -c 6-16)
|
||||||
|
|
||||||
|
if [ "$score" -le 20 ]; then SCORE_EMJ="🟢"
|
||||||
|
elif [ "$score" -le 60 ]; then SCORE_EMJ="🟡"
|
||||||
|
else SCORE_EMJ="🔴"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 拼接紧凑排版
|
||||||
|
TEXT_RES+="\`${short_time}\` | ${SCORE_EMJ}\`${score}\` | \`${goog}\` | \`${nf}\` | \`${gpt}\`\n"
|
||||||
|
done <<< "$TREND_DATA"
|
||||||
|
TEXT_RES+="\n_💡 提示:🔴风险分 >60 极易触发网页验证码拦截;谷歌显示 CN 即为高危送中。_"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# [v4.0.3 体验升级] 注入交互式控制台按钮,并调用原生 UI 重绘函数
|
||||||
|
BTNS="[[{\"text\":\"⚙️ 调出该节点控制台\",\"callback_data\":\"manage:$TARGET_NODE\"}]]"
|
||||||
|
|
||||||
|
if [ -n "$MSG_ID" ]; then
|
||||||
|
edit_ui "$CHAT_ID" "$MSG_ID" "$TEXT_RES" "$BTNS"
|
||||||
|
else
|
||||||
|
send_ui "$CHAT_ID" "$TEXT_RES" "$BTNS"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -5,6 +5,15 @@
|
|||||||
# 核心功能: 终止调度进程、清理看门狗定时任务、抹除数据库与配置
|
# 核心功能: 终止调度进程、清理看门狗定时任务、抹除数据库与配置
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
|
|
||||||
|
# ==========================================================
|
||||||
|
# 🛑 核心权限防线: 检查是否以 root 权限运行
|
||||||
|
# ==========================================================
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
echo -e "\033[31m❌ 权限被拒绝: 卸载 IP-Sentinel 需要最高系统权限。\033[0m"
|
||||||
|
echo -e "💡 请切换到 root 用户 (执行 su root 或 sudo -i) 后重新运行指令。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
MASTER_DIR="/opt/ip_sentinel_master"
|
MASTER_DIR="/opt/ip_sentinel_master"
|
||||||
CONF_FILE="${MASTER_DIR}/master.conf"
|
CONF_FILE="${MASTER_DIR}/master.conf"
|
||||||
|
|
||||||
@@ -25,19 +34,31 @@ if [[ ! "$CONFIRM_DEL" =~ ^[Yy]$ ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 1. 停止运行中的 Master 守护进程
|
# 1. 停止并删除 Systemd 服务 (适配新架构)
|
||||||
echo "[1/3] 正在终止后台中枢调度进程..."
|
echo "[1/4] 正在停止并删除 Systemd 服务..."
|
||||||
# [优化] 使用 pkill 替代 pgrep | xargs,指令更短、容错率更高
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
|
echo "💡 检测到 Systemd 环境,正在抹除 Systemd 服务单元..."
|
||||||
|
# [防死锁修复] 先发送 SIGKILL 瞬间抹杀,防止卡死
|
||||||
|
systemctl kill --signal=SIGKILL ip-sentinel-master.service >/dev/null 2>&1 || true
|
||||||
|
systemctl disable --now ip-sentinel-master.service >/dev/null 2>&1
|
||||||
|
rm -f /etc/systemd/system/ip-sentinel-master.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl reset-failed
|
||||||
|
else
|
||||||
|
echo "💡 未检测到 Systemd,跳过此步骤..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 停止运行中的 Master 守护进程 (兜底清理老版进程)
|
||||||
|
echo "[2/4] 正在终止后台中枢调度进程..."
|
||||||
pkill -9 -f "tg_master.sh" >/dev/null 2>&1 || true
|
pkill -9 -f "tg_master.sh" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
# 2. 清除看门狗定时任务 (Cron)
|
# 3. 清除看门狗定时任务 (Cron)
|
||||||
echo "[2/3] 正在清理系统定时任务 (Cron)..."
|
echo "[3/4] 正在清理系统定时任务 (Cron)..."
|
||||||
crontab -l 2>/dev/null | grep -v "tg_master.sh" > /tmp/cron_backup
|
# [终极防御] 内存管道流过滤,绝不写硬盘
|
||||||
crontab /tmp/cron_backup
|
crontab -l 2>/dev/null | grep -v "tg_master.sh" | crontab - >/dev/null 2>&1 || true
|
||||||
rm -f /tmp/cron_backup
|
|
||||||
|
|
||||||
# 3. 删除所有文件、配置与数据库
|
# 4. 删除所有文件、配置与数据库
|
||||||
echo "[3/3] 正在抹除核心程序、配置文件与 SQLite 数据库..."
|
echo "[4/4] 正在抹除核心程序、配置文件与 SQLite 数据库..."
|
||||||
if [ -d "$MASTER_DIR" ]; then
|
if [ -d "$MASTER_DIR" ]; then
|
||||||
rm -rf "$MASTER_DIR"
|
rm -rf "$MASTER_DIR"
|
||||||
fi
|
fi
|
||||||
|
|||||||
104
scripts/fetch_trust_urls.py
Normal file
104
scripts/fetch_trust_urls.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import urllib.request
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
|
||||||
|
# ================== [路径防弹装甲] ==================
|
||||||
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
PROJECT_ROOT = os.path.dirname(SCRIPT_DIR)
|
||||||
|
REGIONS_DIR = os.path.join(PROJECT_ROOT, "data", "regions")
|
||||||
|
# ====================================================
|
||||||
|
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 全球骨干新闻 RSS 监听矩阵
|
||||||
|
RSS_FEEDS = {
|
||||||
|
"US": ["http://rss.cnn.com/rss/cnn_topstories.rss", "https://feeds.npr.org/1001/rss.xml"],
|
||||||
|
"UK": ["http://feeds.bbci.co.uk/news/rss.xml"],
|
||||||
|
"AU": ["https://www.abc.net.au/news/feed/51120/rss.xml"],
|
||||||
|
"CA": ["https://www.cbc.ca/cmlink/rss-topstories"],
|
||||||
|
"DE": ["https://www.tagesschau.de/xml/rss2"],
|
||||||
|
"FR": ["https://www.france24.com/fr/rss"],
|
||||||
|
"ES": ["https://feeds.elpais.com/mrss-s/pages/ep/site/elpais.com/portada"],
|
||||||
|
"JP": ["https://news.yahoo.co.jp/rss/topics/top-picks.xml"],
|
||||||
|
"HK": ["https://hk.news.yahoo.com/rss/hong-kong"],
|
||||||
|
"TW": ["https://news.google.com/rss?hl=zh-TW&gl=TW&ceid=TW:zh-Hant"],
|
||||||
|
"KR": ["https://www.yonhapnewstv.co.kr/category/news/headline/feed/"],
|
||||||
|
"SG": ["https://www.channelnewsasia.com/api/v1/rss-outbound-feed?_format=xml"],
|
||||||
|
"NL": ["https://feeds.nos.nl/nosnieuwsalgemeen"],
|
||||||
|
"VN": ["https://vnexpress.net/rss/tin-moi-nhat.rss"],
|
||||||
|
"MY": ["https://news.google.com/rss?hl=en-MY&gl=MY&ceid=MY:en"],
|
||||||
|
"NG": ["https://punchng.com/feed/", "https://guardian.ng/feed/"]
|
||||||
|
}
|
||||||
|
|
||||||
|
def fetch_rss_links(region_code, max_items=15):
|
||||||
|
"""抓取该战区最新的 RSS 新闻链接"""
|
||||||
|
feeds = RSS_FEEDS.get(region_code, [])
|
||||||
|
if not feeds:
|
||||||
|
return []
|
||||||
|
|
||||||
|
links = []
|
||||||
|
for url in feeds:
|
||||||
|
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)
|
||||||
|
for item in root.findall('.//item'):
|
||||||
|
link = item.find('link')
|
||||||
|
if link is not None and link.text:
|
||||||
|
clean_link = link.text.strip()
|
||||||
|
if clean_link.startswith('http'):
|
||||||
|
links.append(clean_link)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ [{region_code}] RSS 抓取异常 ({url}): {e}")
|
||||||
|
|
||||||
|
# 去重并截取最新
|
||||||
|
return list(set(links))[:max_items]
|
||||||
|
|
||||||
|
def process_json_file(file_path, region_code):
|
||||||
|
"""融合静态基石与动态新闻"""
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
trust_mod = data.get("trust_module", {})
|
||||||
|
if not trust_mod or "static_urls" not in trust_mod:
|
||||||
|
return
|
||||||
|
|
||||||
|
static_urls = trust_mod.get("static_urls", [])
|
||||||
|
|
||||||
|
# 抓取今日该战区的活体新闻流
|
||||||
|
daily_news_urls = fetch_rss_links(region_code)
|
||||||
|
|
||||||
|
# 战术混合:基石(保证高权重) + 新闻(保证活体动态)
|
||||||
|
combined_urls = static_urls + daily_news_urls
|
||||||
|
|
||||||
|
# 深度洗牌,打破机械顺序特征
|
||||||
|
combined_urls = list(set(combined_urls))
|
||||||
|
random.shuffle(combined_urls)
|
||||||
|
|
||||||
|
# 覆写回供 Agent 拉取的 white_urls
|
||||||
|
trust_mod["white_urls"] = combined_urls
|
||||||
|
data["trust_module"] = trust_mod
|
||||||
|
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
print(f"✅ [信用融合] {os.path.basename(file_path)}: 骨干 {len(static_urls)} 条 + 活体 {len(daily_news_urls)} 条")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ [处理失败] {file_path}: {e}")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("========== 启动 IP-Sentinel 活体新闻流融合引擎 ==========")
|
||||||
|
for root_dir, _, files in os.walk(REGIONS_DIR):
|
||||||
|
for file in files:
|
||||||
|
if file.endswith(".json"):
|
||||||
|
file_path = os.path.join(root_dir, file)
|
||||||
|
region_code = os.path.relpath(file_path, REGIONS_DIR).split(os.sep)[0]
|
||||||
|
process_json_file(file_path, region_code)
|
||||||
|
print("========== 融合引擎执行完毕 ==========")
|
||||||
@@ -1 +1,2 @@
|
|||||||
3.5.0
|
MASTER_VERSION=4.0.7
|
||||||
|
AGENT_VERSION=4.0.6
|
||||||
|
|||||||
Reference in New Issue
Block a user