Update get_vpn.py
This commit is contained in:
+210
-86
@@ -2,6 +2,12 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
except ImportError:
|
||||||
|
print("Ошибка: Отсутствует библиотека PyYAML. Установите её командой: pip install pyyaml")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def fetch_and_prepare_configs():
|
def fetch_and_prepare_configs():
|
||||||
# Забираем ссылку из секретов Gitea/GitHub
|
# Забираем ссылку из секретов Gitea/GitHub
|
||||||
@@ -26,102 +32,220 @@ def fetch_and_prepare_configs():
|
|||||||
try:
|
try:
|
||||||
print("Отправка запроса к серверу VPN...")
|
print("Отправка запроса к серверу VPN...")
|
||||||
response = requests.get(sub_url, headers=headers, timeout=20)
|
response = requests.get(sub_url, headers=headers, timeout=20)
|
||||||
|
response.raise_for_status() # Вызовет ошибку при статусе не 200
|
||||||
if response.status_code != 200:
|
|
||||||
print(
|
|
||||||
f"Ошибка сервера: Статус {response.status_code}. Проверьте ссылку-подписку."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
raw_content = response.text.strip()
|
raw_content = response.text.strip()
|
||||||
|
|
||||||
# Проверяем, что в ответе реально есть сервера
|
|
||||||
if "proxies:" not in raw_content:
|
|
||||||
print(
|
|
||||||
"Ошибка: Сервер вернул YAML, но в нём отсутствует блок нод 'proxies:'."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# ФАЙЛ 1: Сохраняем оригинальный чистый конфиг от провайдера
|
# ФАЙЛ 1: Сохраняем оригинальный чистый конфиг от провайдера
|
||||||
with open("clash.yaml", "w", encoding="utf-8") as f:
|
with open("clash.yaml", "w", encoding="utf-8") as f:
|
||||||
f.write(raw_content)
|
f.write(raw_content)
|
||||||
print("Оригинальный конфиг успешно сохранен в clash.yaml")
|
print("Оригинальный конфиг успешно сохранен в clash.yaml")
|
||||||
|
|
||||||
# ФАЙЛ 2: Создаем модифицированный конфиг для раздельного обхода
|
# Парсим YAML в словарь Python для безопасного редактирования
|
||||||
# Переводим режим работы в rule (по правилам) вместо global (весь трафик)
|
config = yaml.safe_load(raw_content)
|
||||||
split_content = raw_content.replace("mode: global", "mode: rule")
|
if not isinstance(config, dict):
|
||||||
|
print("Ошибка: Не удалось распарсить YAML конфиг. Проверьте ссылку-подписку.")
|
||||||
if "rules:" in split_content:
|
|
||||||
# Отрезаем старые правила провайдера (всё, что после 'rules:')
|
|
||||||
base_part = split_content.split("rules:")[0]
|
|
||||||
|
|
||||||
# Формируем огромный расширенный список правил с разделением трафика
|
|
||||||
advanced_rules = """rules:
|
|
||||||
# 1. Локальные адреса и домашняя сеть (в обход VPN)
|
|
||||||
- DOMAIN-SUFFIX,local,DIRECT
|
|
||||||
- IP-CIDR,127.0.0.0/8,DIRECT
|
|
||||||
- IP-CIDR,172.16.0.0/12,DIRECT
|
|
||||||
- IP-CIDR,192.168.0.0/16,DIRECT
|
|
||||||
- IP-CIDR,10.0.0.0/8,DIRECT
|
|
||||||
- IP-CIDR,198.18.0.0/16,DIRECT
|
|
||||||
|
|
||||||
# 2. Популярные заблокированные ресурсы и сервисы (через VPN)
|
|
||||||
- GEOSITE,onion,→ Remnawave
|
|
||||||
- GEOSITE,twitter,→ Remnawave
|
|
||||||
- GEOSITE,instagram,→ Remnawave
|
|
||||||
- GEOSITE,facebook,→ Remnawave
|
|
||||||
- GEOSITE,meta,→ Remnawave
|
|
||||||
- GEOSITE,youtube,→ Remnawave
|
|
||||||
- GEOSITE,netflix,→ Remnawave
|
|
||||||
- GEOSITE,openai,→ Remnawave
|
|
||||||
- GEOSITE,chatgpt,→ Remnawave
|
|
||||||
- GEOSITE,discord,→ Remnawave
|
|
||||||
- GEOSITE,protonmail,→ Remnawave
|
|
||||||
- GEOSITE,intel,→ Remnawave
|
|
||||||
- GEOSITE,amd,→ Remnawave
|
|
||||||
- GEOSITE,nvidia,→ Remnawave
|
|
||||||
- GEOSITE,spotify,→ Remnawave
|
|
||||||
- GEOSITE,linkedin,→ Remnawave
|
|
||||||
- GEOSITE,rutracker,→ Remnawave
|
|
||||||
- GEOSITE,notion,→ Remnawave
|
|
||||||
- GEOSITE,docker,→ Remnawave
|
|
||||||
- GEOSITE,medium,→ Remnawave
|
|
||||||
- GEOSITE,behance,→ Remnawave
|
|
||||||
- GEOSITE,pinterest,→ Remnawave
|
|
||||||
- GEOSITE,canva,→ Remnawave
|
|
||||||
- GEOSITE,epicgames,→ Remnawave
|
|
||||||
|
|
||||||
# 3. Весь остальной зарубежный контент (по желанию, через VPN)
|
|
||||||
- GEOSITE,geolocation-!cn,→ Remnawave
|
|
||||||
|
|
||||||
# 4. Российские государственные сайты, банки и крупные ресурсы (напрямую, без VPN)
|
|
||||||
- GEOSITE,win-russia,DIRECT
|
|
||||||
- GEOSITE,category-gov-ru,DIRECT
|
|
||||||
- GEOSITE,ru,DIRECT
|
|
||||||
- GEOSITE,yandex,DIRECT
|
|
||||||
- GEOSITE,vk,DIRECT
|
|
||||||
- GEOSITE,mailru,DIRECT
|
|
||||||
- GEOSITE,sberbank,DIRECT
|
|
||||||
- GEOSITE,tinkoff,DIRECT
|
|
||||||
- GEOSITE,kinopoisk,DIRECT
|
|
||||||
- GEOSITE,avito,DIRECT
|
|
||||||
- GEOIP,RU,DIRECT
|
|
||||||
|
|
||||||
# 5. Финальное замыкающее правило: всё, что не подошло под списки выше, идет НАПРЯМУЮ
|
|
||||||
- MATCH,DIRECT
|
|
||||||
"""
|
|
||||||
# Склеиваем настройки и новые правила
|
|
||||||
full_split_yaml = base_part + advanced_rules
|
|
||||||
|
|
||||||
with open("clash_split.yaml", "w", encoding="utf-8") as f:
|
|
||||||
f.write(full_split_yaml)
|
|
||||||
print("Раздельный конфиг успешно сохранен в clash_split.yaml")
|
|
||||||
else:
|
|
||||||
print(
|
|
||||||
"Ошибка: В исходном конфиге не найдена секция rules: для замены!"
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# 1. Базовые настройки
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# ВАЖНО: Для работы правил (раздельного обхода) режим должен быть 'rule', а не 'global'
|
||||||
|
config['mode'] = 'rule'
|
||||||
|
config['external-controller'] = '0.0.0.0:9090'
|
||||||
|
config['ipv6'] = False
|
||||||
|
config['keep-alive-idle'] = 30
|
||||||
|
config['keep-alive-interval'] = 15
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# 2. Заменяем секцию DNS
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
config['dns'] = {
|
||||||
|
'enable': True,
|
||||||
|
'use-hosts': True,
|
||||||
|
'enhanced-mode': 'fake-ip',
|
||||||
|
'fake-ip-range': '198.18.0.1/16',
|
||||||
|
'default-nameserver': ['77.88.8.8', '8.8.8.8'],
|
||||||
|
'nameserver': ['77.88.8.8', '77.88.8.1'],
|
||||||
|
'fake-ip-filter': [
|
||||||
|
"*.lan", "stun.*.*.*", "stun.*.*", "time.windows.com",
|
||||||
|
"time.nist.gov", "time.apple.com", "time.asia.apple.com",
|
||||||
|
"*.openwrt.pool.ntp.org", "pool.ntp.org", "ntp.ubuntu.com",
|
||||||
|
"time1.apple.com", "time2.apple.com", "time3.apple.com",
|
||||||
|
"time4.apple.com", "time5.apple.com", "time6.apple.com",
|
||||||
|
"time7.apple.com", "time1.google.com", "time2.google.com",
|
||||||
|
"time3.google.com", "time4.google.com", "api.joox.com",
|
||||||
|
"joox.com", "*.xiami.com", "*.msftconnecttest.com",
|
||||||
|
"*.msftncsi.com", "+.xboxlive.com", "*.*.stun.playstation.net",
|
||||||
|
"xbox.*.*.microsoft.com", "*.ipv6.microsoft.com",
|
||||||
|
"speedtest.cros.wr.pvp.net"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# 3. Формируем группу Proxy (url-test)
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Собираем все имена прокси из оригинального конфига
|
||||||
|
proxy_names = []
|
||||||
|
if 'proxies' in config and isinstance(config['proxies'], list):
|
||||||
|
# Если есть верхнеуровневый список proxies (стандарт Clash)
|
||||||
|
proxy_names = [p.get('name') for p in config['proxies'] if isinstance(p, dict) and 'name' in p]
|
||||||
|
else:
|
||||||
|
# Фолбэк: собираем имена из существующих групп proxy-groups
|
||||||
|
for group in config.get('proxy-groups', []):
|
||||||
|
if isinstance(group, dict) and 'proxies' in group:
|
||||||
|
proxy_names.extend(group['proxies'])
|
||||||
|
# Убираем дубликаты, сохраняя порядок
|
||||||
|
proxy_names = list(dict.fromkeys(proxy_names))
|
||||||
|
|
||||||
|
new_proxy_group = {
|
||||||
|
'name': 'Proxy',
|
||||||
|
'type': 'url-test',
|
||||||
|
'proxies': proxy_names,
|
||||||
|
'url': 'http://www.gstatic.com/generate_204',
|
||||||
|
'interval': 300,
|
||||||
|
'tolerance': 50
|
||||||
|
}
|
||||||
|
|
||||||
|
# Заменяем старую главную группу (например, "→ Remnawave" или "PROXY") на новую
|
||||||
|
updated_groups = []
|
||||||
|
replaced = False
|
||||||
|
for group in config.get('proxy-groups', []):
|
||||||
|
if isinstance(group, dict) and group.get('name') in ['→ Remnawave', 'PROXY', 'Proxy']:
|
||||||
|
updated_groups.append(new_proxy_group)
|
||||||
|
replaced = True
|
||||||
|
else:
|
||||||
|
updated_groups.append(group)
|
||||||
|
|
||||||
|
# Если такой группы не было, добавляем её в начало
|
||||||
|
if not replaced:
|
||||||
|
updated_groups.insert(0, new_proxy_group)
|
||||||
|
|
||||||
|
config['proxy-groups'] = updated_groups
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# 4. Заменяем правила (rules)
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
config['rules'] = [
|
||||||
|
"RULE-SET,telegram,Proxy",
|
||||||
|
"RULE-SET,geosite-discord,Proxy",
|
||||||
|
"RULE-SET,discord-voice,Proxy",
|
||||||
|
"RULE-SET,geosite-whatsapp,Proxy",
|
||||||
|
"RULE-SET,geosite-viber,Proxy",
|
||||||
|
"RULE-SET,geosite-signal,Proxy",
|
||||||
|
"RULE-SET,geosite-youtube,Proxy",
|
||||||
|
"RULE-SET,geosite-twitter,Proxy",
|
||||||
|
"RULE-SET,geosite-facebook,Proxy",
|
||||||
|
"RULE-SET,geosite-instagram,Proxy",
|
||||||
|
"RULE-SET,geosite-openai,Proxy",
|
||||||
|
"RULE-SET,geosite-anthropic,Proxy",
|
||||||
|
"RULE-SET,geosite-google-gemini,Proxy",
|
||||||
|
"RULE-SET,geosite-xai,Proxy",
|
||||||
|
"RULE-SET,cdn-all,Proxy",
|
||||||
|
"DOMAIN-SUFFIX,com,Proxy",
|
||||||
|
"RULE-SET,ru-blocked,Proxy",
|
||||||
|
"GEOIP,RU,DIRECT",
|
||||||
|
"MATCH,DIRECT"
|
||||||
|
]
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# 5. Добавляем rule-providers
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
config['rule-providers'] = {
|
||||||
|
'geosite-discord': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/discord.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-whatsapp': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/whatsapp.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-viber': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/viber.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-signal': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/signal.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-youtube': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/youtube.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-twitter': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/twitter.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-facebook': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/facebook.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-instagram': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/instagram.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-openai': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/openai.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-anthropic': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/anthropic.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-google-gemini': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/google-gemini.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'geosite-xai': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/refs/heads/meta/geo/geosite/xai.yaml',
|
||||||
|
'interval': 86400
|
||||||
|
},
|
||||||
|
'cdn-all': {
|
||||||
|
'behavior': 'ipcidr', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/123jjck/cdn-ip-ranges/refs/heads/main/cdn-only/cdn-only_plain_ipv4.txt',
|
||||||
|
'interval': 86400, 'format': 'text'
|
||||||
|
},
|
||||||
|
'telegram': {
|
||||||
|
'behavior': 'ipcidr', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/123jjck/cdn-ip-ranges/refs/heads/main/telegram/telegram_plain_ipv4.txt',
|
||||||
|
'interval': 86400, 'format': 'text'
|
||||||
|
},
|
||||||
|
'discord-voice': {
|
||||||
|
'behavior': 'ipcidr', 'type': 'http',
|
||||||
|
'url': 'https://raw.githubusercontent.com/123jjck/cdn-ip-ranges/refs/heads/main/discord-voice/discord-voice_plain_ipv4.txt',
|
||||||
|
'interval': 86400, 'format': 'text'
|
||||||
|
},
|
||||||
|
'ru-blocked': {
|
||||||
|
'behavior': 'domain', 'type': 'http',
|
||||||
|
'url': 'https://cdn.jsdelivr.net/gh/shvchk/unblock-net/lists/clash/ru-blocked',
|
||||||
|
'interval': 86400, 'format': 'text'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ФАЙЛ 2: Сохраняем модифицированный конфиг
|
||||||
|
with open("clash_split.yaml", "w", encoding="utf-8") as f:
|
||||||
|
# sort_keys=False сохраняет исходный порядок ключей
|
||||||
|
# allow_unicode=True гарантирует, что эмодзи (🇩🇪, 🇷🇺) не превратятся в \u-последовательности
|
||||||
|
# width=1000 предотвращает нежелательный перенос длинных строк
|
||||||
|
yaml.dump(config, f, default_flow_style=False, sort_keys=False, allow_unicode=True, width=1000)
|
||||||
|
|
||||||
|
print("Раздельный конфиг успешно сохранен в clash_split.yaml")
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"Ошибка сети: {e}")
|
||||||
|
sys.exit(1)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Критическая ошибка во время выполнения: {e}")
|
print(f"Критическая ошибка во время выполнения: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
Reference in New Issue
Block a user