mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 07:55:13 +08:00
🦄 Sync 2026-06-05 01:27:09
This commit is contained in:
1 parent
2f80691f7d
commit
f8db3e79f6
64 files changed
+75620
-81561
No files matched your search
File diff suppressed because it is too large.
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
+65227
-70210
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,21 @@
|
||||
rule-providers:
|
||||
## google:
|
||||
## type: http
|
||||
## path: ./rule1.yaml
|
||||
## url: "https://raw.githubusercontent.com/../Google.yaml"
|
||||
## interval: 600
|
||||
## proxy: DIRECT
|
||||
## behavior: classical
|
||||
## format: yaml
|
||||
## size-limit: 0
|
||||
## header:
|
||||
## User-Agent:
|
||||
## - "mihomo/1.18.3"
|
||||
## Authorization:
|
||||
## - 'token 1231231'
|
||||
## payload:
|
||||
## - 'DOMAIN-SUFFIX,google.com'
|
||||
|
||||
rules:
|
||||
##- PROCESS-NAME,curl,DIRECT #匹配路由自身进程(curl直连)
|
||||
##- DOMAIN-SUFFIX,google.com,Proxy #匹配域名后缀(交由Proxy代理服务器组)
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
rule-providers:
|
||||
## google:
|
||||
## type: http
|
||||
## path: ./rule1.yaml
|
||||
## url: "https://raw.githubusercontent.com/../Google.yaml"
|
||||
## interval: 600
|
||||
## proxy: DIRECT
|
||||
## behavior: classical
|
||||
## format: yaml
|
||||
## size-limit: 0
|
||||
## header:
|
||||
## User-Agent:
|
||||
## - "mihomo/1.18.3"
|
||||
## Authorization:
|
||||
## - 'token 1231231'
|
||||
## payload:
|
||||
## - 'DOMAIN-SUFFIX,google.com'
|
||||
rules:
|
||||
##- DOMAIN-SUFFIX,google.com,Proxy #匹配域名后缀(交由Proxy代理服务器组)
|
||||
##- DOMAIN-KEYWORD,google,Proxy #匹配域名关键字(交由Proxy代理服务器组)
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
|
||||
# ENABLE_TCP_CONCURRENT (启用 TCP 并发, 0: 插件不覆写, 1: 启用)
|
||||
# FIND_PROCESS_MODE (进程查找模式, 0: 插件不覆写, off: 关闭, always, strict)
|
||||
# GLOBAL_CLIENT_FINGERPRINT (全局客户端指纹, none/random/chrome/firefox/safari/ios/android/edge/360/qq/0: 插件不覆写)
|
||||
# ENABLE_UNIFIED_DELAY (启用统一延迟计算, 0: 插件不覆写, 1: 启用)
|
||||
|
||||
# ENABLE_RULE_PROXY (仅代理命中规则流量, 0: 禁用, 1: 启用)
|
||||
@@ -117,6 +116,7 @@
|
||||
# GEOASN_CUSTOM_URL (GeoASN 数据自定义更新地址, URL or default)
|
||||
|
||||
# --- 其它功能 ---
|
||||
# GLOBAL_UA (全局 User-Agent, 0:不覆写,或具体 UA)
|
||||
# SMALL_FLASH_MEMORY (小闪存模式, 0: 禁用, 1: 启用)
|
||||
# DISABLE_QUIC_GO_GSO (禁用 QUIC GO GSO, 0: 插件不覆写, 1: 启用)
|
||||
# DELAY_START (延时启动, 0: 禁用 or 秒数)
|
||||
@@ -209,6 +209,298 @@
|
||||
#指定展示订阅信息的 URL 地址
|
||||
#SUB_INFO_URL = https://default-demo.yaml
|
||||
|
||||
# ==========================================================
|
||||
# ==== 以下为 YAML 块覆写示例 ====
|
||||
# ==========================================================
|
||||
# YAML 覆写块识别标记
|
||||
# [YAML]
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 操作符速查表:
|
||||
# key → 默认合并(Hash 递归合并,其他直接覆盖)
|
||||
# key! → 强制覆盖整个值
|
||||
# key+ → 数组后置追加
|
||||
# +key → 数组前置插入
|
||||
# key- → 数组差集删除 / 非数组则删除该键
|
||||
# key* → 批量条件更新(需配合 where/set)
|
||||
# <key>后缀 → 同上(+, !, *, -),适用于键名含特殊字符时
|
||||
# +<key> → 数组前置插入,适用于键名含特殊字符时
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 1. 默认合并 - 合并哈希键值,键不存在则添加,Hash 值递归合并
|
||||
# 示例:修改 dns.enable 并添加新键
|
||||
# dns:
|
||||
# enable: true
|
||||
# cache-algorithm: lru
|
||||
|
||||
# 示例:直接替换标量值
|
||||
# mixed-port: 10802
|
||||
# allow-lan: false
|
||||
|
||||
# 示例:合并 tun 配置(仅修改指定字段,其余保留)
|
||||
# tun:
|
||||
# enable: true
|
||||
# stack: gvisor
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 2. 强制覆盖 (key!) - 强制替换整个值,不做递归合并
|
||||
# 示例:替换整个 dns.fake-ip-filter 数组
|
||||
# dns:
|
||||
# fake-ip-filter!:
|
||||
# - '*.lan'
|
||||
# - 'new.domain.com'
|
||||
|
||||
# 示例:强制覆盖整个 rules 数组
|
||||
# rules!:
|
||||
# - DOMAIN-SUFFIX,example.com,DIRECT
|
||||
# - MATCH,PROXY
|
||||
|
||||
# 示例:使用 <> 强制覆盖整个 dns 配置(键名含特殊字符时)
|
||||
# <dns>!:
|
||||
# enable: false
|
||||
# nameserver:
|
||||
# - '114.114.114.114'
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 3. 数组后置 (key+) - 将新元素追加到数组末尾
|
||||
# 示例:向 dns.nameserver 末尾追加 DNS
|
||||
# dns:
|
||||
# nameserver+:
|
||||
# - '1.1.1.1'
|
||||
# - '8.8.8.8'
|
||||
|
||||
# 示例:向 rules 末尾追加规则
|
||||
# rules+:
|
||||
# - DOMAIN-SUFFIX,example.com,REJECT
|
||||
|
||||
# 示例:使用 <> 后置
|
||||
# dns:
|
||||
# <nameserver>+:
|
||||
# - '8.8.8.8'
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 4. 数组前置 (+key / +<key>) - 将新元素插入到数组开头
|
||||
# 示例:向 dns.nameserver 开头插入 DNS
|
||||
# dns:
|
||||
# +nameserver:
|
||||
# - '223.5.5.5'
|
||||
# - '119.29.29.29'
|
||||
|
||||
# 示例:向 rules 开头插入规则(优先匹配)
|
||||
# +rules:
|
||||
# - DOMAIN-SUFFIX,priority.com,DIRECT
|
||||
|
||||
# 示例:使用 +<> 前置插入(键名含特殊字符时)
|
||||
# dns:
|
||||
# +<nameserver>:
|
||||
# - '119.29.29.29'
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 5. 数组删除 (key-) - 从数组中移除指定元素,非数组则删除整个键
|
||||
# 示例:从 dns.nameserver 中移除指定 DNS
|
||||
# dns:
|
||||
# nameserver-:
|
||||
# - '8.8.8.8'
|
||||
# - '8.8.4.4'
|
||||
|
||||
# 示例:从 rules 中移除指定规则
|
||||
# rules-:
|
||||
# - DOMAIN-SUFFIX,old.com,REJECT
|
||||
|
||||
# 示例:删除整个键(值为 null/~ 或空)
|
||||
# dns:
|
||||
# cache-algorithm-:
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 6. 批量条件更新 (key*) - 按 where 条件匹配集合元素,用 set 子句更新
|
||||
#
|
||||
# 支持的集合类型:
|
||||
# - 数组(元素为 Hash 或 String)
|
||||
# - Hash(值为 Hash)
|
||||
#
|
||||
# where 条件支持:
|
||||
# - 普通值相等: type: select
|
||||
# - 正则匹配: name: '/^HK/'
|
||||
# - 数组包含: proxies: ['proxy1'] (检查数组是否包含所有指定元素)
|
||||
# - Hash 键匹配: key: 'some-key' (仅用于 Hash 类型集合)
|
||||
# - 字符串匹配: value: 'some-string' (仅用于字符串数组)
|
||||
#
|
||||
# set 子句支持的操作符(同顶层操作符):
|
||||
# field → 直接覆盖该字段
|
||||
# field! → 强制覆盖该字段
|
||||
# field+ → 数组后置追加
|
||||
# +field → 数组前置插入
|
||||
# field- → 数组差集删除 / 非数组则删除该键
|
||||
# value → 替换字符串数组中的匹配项
|
||||
# value: ~ → 删除字符串数组中的匹配项
|
||||
# key: ~ → 删除 Hash 中的匹配键(仅 Hash 集合)
|
||||
# key-: → 同上
|
||||
|
||||
# 示例:按 type 匹配,替换 proxy-groups 的 proxies
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# type: select
|
||||
# set:
|
||||
# proxies:
|
||||
# - 'new-proxy1'
|
||||
# - 'new-proxy2'
|
||||
|
||||
# 示例:按 type 匹配,向 proxies 末尾追加节点
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# type: select
|
||||
# set:
|
||||
# proxies+:
|
||||
# - 'new-proxy3'
|
||||
|
||||
# 示例:按 type 匹配,向 proxies 开头插入节点
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# type: url-test
|
||||
# set:
|
||||
# +proxies:
|
||||
# - 'new-proxy1'
|
||||
|
||||
# 示例:按 type 匹配,从 proxies 中移除指定节点
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# type: select
|
||||
# set:
|
||||
# proxies-:
|
||||
# - 'old-proxy1'
|
||||
# - 'old-proxy2'
|
||||
|
||||
# 示例:使用数组包含条件(proxies 中必须包含指定元素才匹配)
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# type: select
|
||||
# proxies:
|
||||
# - 'old-proxy1'
|
||||
# set:
|
||||
# proxies:
|
||||
# - 'new-proxy1'
|
||||
# - 'new-proxy2'
|
||||
|
||||
# 示例:使用正则匹配 name 字段
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# name: '/^HK/'
|
||||
# set:
|
||||
# +proxies:
|
||||
# - 'hk-new-proxy'
|
||||
|
||||
# 示例:删除 proxy-groups 中某个字段(set value 为 null/~)
|
||||
# proxy-groups*:
|
||||
# where:
|
||||
# name: Proxy
|
||||
# set:
|
||||
# icon-:
|
||||
|
||||
# 示例:按 type 匹配修改 proxies 中 socks5 节点端口
|
||||
# proxies*:
|
||||
# where:
|
||||
# type: socks5
|
||||
# set:
|
||||
# port: 1080
|
||||
|
||||
# 示例:更新 hosts Hash 中的指定键
|
||||
# hosts*:
|
||||
# where:
|
||||
# key: '*.mihomo.dev'
|
||||
# set:
|
||||
# '*.mihomo.dev': '::1'
|
||||
|
||||
# 示例:删除 hosts Hash 中的匹配键
|
||||
# hosts*:
|
||||
# where:
|
||||
# key: '*.old.dev'
|
||||
# set:
|
||||
# key-:
|
||||
|
||||
# 示例:替换字符串数组中的匹配项
|
||||
# rules*:
|
||||
# where:
|
||||
# value: 'DOMAIN-SUFFIX,old.com,REJECT'
|
||||
# set:
|
||||
# value: 'DOMAIN-SUFFIX,new.com,DIRECT'
|
||||
|
||||
# 示例:使用正则匹配并删除字符串数组中的规则
|
||||
# rules*:
|
||||
# where:
|
||||
# value: '/,REJECT$/'
|
||||
# set:
|
||||
# value:
|
||||
|
||||
# 示例:删除 fake-ip-filter 中的指定项
|
||||
# dns:
|
||||
# fake-ip-filter*:
|
||||
# where:
|
||||
# value: '+.localhost.ptlogin2.qq.com'
|
||||
# set:
|
||||
# value:
|
||||
|
||||
# 示例:使用 <> 批量更新
|
||||
# <proxy-groups>*:
|
||||
# where:
|
||||
# type: url-test
|
||||
# set:
|
||||
# interval: 300
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 7. 组合操作 - 在同一块内同时使用多个操作符
|
||||
# 示例:同时前置和后置追加 DNS(必须写在同一 dns 块内)
|
||||
# dns:
|
||||
# nameserver+:
|
||||
# - '1.0.0.1'
|
||||
# +nameserver:
|
||||
# - '119.29.29.29'
|
||||
|
||||
# 示例:同时删除旧 DNS 并前置插入新 DNS
|
||||
# dns:
|
||||
# nameserver-:
|
||||
# - '8.8.8.8'
|
||||
# +nameserver:
|
||||
# - '223.5.5.5'
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
# 8. <key> 语法补充 - 适用于键名含特殊字符时
|
||||
# 后缀支持:+(后置)、-(删除)、!(强制覆盖)、*(批量更新),空串为默认合并
|
||||
# 前置插入请使用 +<key> 写法(前缀形式)
|
||||
|
||||
# 示例:使用 <> 后置追加
|
||||
# dns:
|
||||
# <nameserver>+:
|
||||
# - '8.8.8.8'
|
||||
|
||||
# 示例:使用 <> 删除数组元素
|
||||
# dns:
|
||||
# <nameserver>-:
|
||||
# - '8.8.8.8'
|
||||
|
||||
# 示例:使用 <> 强制覆盖
|
||||
# dns:
|
||||
# <nameserver>!:
|
||||
# - '114.114.114.114'
|
||||
|
||||
# 示例:使用 <> 批量更新(等同于 key*)
|
||||
# <proxy-groups>*:
|
||||
# where:
|
||||
# type: url-test
|
||||
# set:
|
||||
# interval: 300
|
||||
|
||||
# 示例:使用 +<> 前置插入(键名含特殊字符时的前置写法)
|
||||
# dns:
|
||||
# +<nameserver>:
|
||||
# - '119.29.29.29'
|
||||
|
||||
# ==========================================================
|
||||
# ==== 以下为仅修改插件设置示例 ====
|
||||
# ==========================================================
|
||||
|
||||
Binary file not shown.
@@ -174,8 +174,10 @@ if [ -f "/tmp/openclash.bak" ]; then
|
||||
cp -rf "/tmp/openclash/." "/etc/openclash/" >/dev/null 2>&1
|
||||
#ui
|
||||
if [ -d "/tmp/openclash_ui/" ]; then
|
||||
rm -rf "/usr/share/openclash/ui/" >/dev/null 2>&1
|
||||
cp -rf "/tmp/openclash_ui/." "/usr/share/openclash/ui/" >/dev/null 2>&1
|
||||
if [ -d "/tmp/openclash_ui/metacubexd/" ] || [ -d "/tmp/openclash_ui/zashboard/" ] || [ -d "/tmp/openclash_ui/yacd/" ] || [ -d "/tmp/openclash_ui/dashboard/" ]; then
|
||||
rm -rf "/usr/share/openclash/ui/" >/dev/null 2>&1
|
||||
cp -rf "/tmp/openclash_ui/." "/usr/share/openclash/ui/" >/dev/null 2>&1
|
||||
fi
|
||||
rm -rf "/tmp/openclash_ui/" >/dev/null 2>&1
|
||||
fi
|
||||
#pac
|
||||
@@ -264,6 +266,6 @@ sed -i '/.*kB maximum content size*/c\export let HTTP_MAX_CONTENT = 1024*10240;
|
||||
|
||||
/etc/init.d/uhttpd restart >/dev/null 2>&1
|
||||
|
||||
rm -f /tmp/luci-indexcache >/dev/null 2>&1
|
||||
rm -f /tmp/luci-indexcache.* >/dev/null 2>&1
|
||||
rm -rf /tmp/luci-indexcache /tmp/luci-indexcache.* /var/luci-indexcache /var/luci-indexcache.* >/dev/null 2>&1
|
||||
rm -rf /tmp/luci-modulecache /var/luci-modulecache >/dev/null 2>&1
|
||||
exit 0
|
||||
@@ -1,119 +1,457 @@
|
||||
module YAML
|
||||
class << self
|
||||
alias_method :load, :unsafe_load if YAML.respond_to? :unsafe_load
|
||||
alias_method :original_dump, :dump
|
||||
alias_method :original_load_file, :load_file
|
||||
end
|
||||
class << self
|
||||
alias_method :load, :unsafe_load if YAML.respond_to? :unsafe_load
|
||||
alias_method :original_dump, :dump
|
||||
alias_method :original_load_file, :load_file
|
||||
end
|
||||
|
||||
def self.LOG(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Info] " + "#{info}"
|
||||
end
|
||||
def self.LOG(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Info] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_ERROR(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Error] " + "#{info}"
|
||||
end
|
||||
def self.LOG_ERROR(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Error] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_WARN(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Warning] " + "#{info}"
|
||||
end
|
||||
def self.LOG_WARN(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Warning] " + "#{info}"
|
||||
end
|
||||
|
||||
def self.LOG_TIP(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Tip] " + "#{info}"
|
||||
end
|
||||
def self.LOG_TIP(info)
|
||||
puts Time.new.strftime("%Y-%m-%d %H:%M:%S") + " [Tip] " + "#{info}"
|
||||
end
|
||||
|
||||
# Keep `short-id` as string before YAML parsing so leading zeros are preserved.
|
||||
# This is required for REALITY short-id values like `00000000`.
|
||||
def self.load_file(filename, *args, **kwargs)
|
||||
yaml_content = File.read(filename)
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
def self.load_file(filename, *args, **kwargs)
|
||||
yaml_content = File.read(filename)
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
|
||||
if kwargs.empty?
|
||||
load(processed_content, *args)
|
||||
else
|
||||
load(processed_content, *args, **kwargs)
|
||||
end
|
||||
end
|
||||
load(processed_content, *args, **kwargs)
|
||||
end
|
||||
|
||||
def self.dump(obj, io = nil, **options)
|
||||
begin
|
||||
if io.nil?
|
||||
yaml_content = original_dump(obj, **options)
|
||||
fix_short_id_quotes(yaml_content)
|
||||
elsif io.respond_to?(:write)
|
||||
require 'stringio'
|
||||
temp_io = StringIO.new
|
||||
original_dump(obj, temp_io, **options)
|
||||
yaml_content = temp_io.string
|
||||
processed_content = fix_short_id_quotes(yaml_content)
|
||||
io.write(processed_content)
|
||||
io
|
||||
else
|
||||
yaml_content = original_dump(obj, io, **options)
|
||||
fix_short_id_quotes(yaml_content)
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Write file failed:【%s】" % [e.message])
|
||||
nil
|
||||
end
|
||||
end
|
||||
def self.dump(obj, io = nil, **options)
|
||||
begin
|
||||
yaml_content = original_dump(obj, **options)
|
||||
processed = fix_short_id_quotes(yaml_content)
|
||||
if io.nil?
|
||||
processed
|
||||
elsif io.respond_to?(:write)
|
||||
io.write(processed)
|
||||
io
|
||||
else
|
||||
processed
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Write file failed:【%s】" % [e.message])
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
SHORT_ID_REGEX = /^(\s*)short-id:\s*(.*)$/
|
||||
LIST_ITEM_REGEX = /^(\s*)-\s*(.*)$/
|
||||
KEY_REGEX = /^(\s*)([a-zA-Z0-9_-]+):\s*(.*)$/
|
||||
QUOTED_VALUE_REGEX = /^["'].*["']$/
|
||||
# fix_short_id_quotes:
|
||||
# Purpose: ensure YAML `short-id` values are emitted with the intended
|
||||
# representation when dumping or re-writing YAML files.
|
||||
# Behavior:
|
||||
# - Non-null, non-empty scalar `short-id` values (and items inside
|
||||
# `short-id` sequences) are written as double-quoted strings.
|
||||
# - Empty strings are preserved as empty quoted strings ("" remains "").
|
||||
# - Null values are preserved and may be emitted explicitly (e.g. `! "").
|
||||
# Lastly, use gsub to clean up any `! ""` tags
|
||||
# Examples:
|
||||
# Input: short-id: 00000000 -> Output: short-id: "00000000"
|
||||
# Input: short-id: "" -> Output: short-id: ""
|
||||
# Input: short-id: "abc123" -> Output: short-id: "abc123"
|
||||
# Input: short-id: "1600e237" -> Output: short-id: "1600e237"
|
||||
# Input: short-id: null -> Output: short-id: ""
|
||||
|
||||
# Inline map support, e.g. reality-opts: { ..., short-id: 00000000 }
|
||||
INLINE_SHORT_ID_REGEX = /(short-id:\s*)(?!["'\[])([^\s,"'{}\[\]\n\r]+)(?=\s*(?:[,}\]\n\r]|$))/m.freeze
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
return yaml_content unless yaml_content.include?('short-id:')
|
||||
|
||||
def self.fix_short_id_quotes(yaml_content)
|
||||
return yaml_content unless yaml_content.include?('short-id:')
|
||||
begin
|
||||
stream = Psych.parse_stream(yaml_content)
|
||||
|
||||
begin
|
||||
# First, normalize inline-map style unquoted short-id.
|
||||
processed = yaml_content.gsub(INLINE_SHORT_ID_REGEX) do
|
||||
"#{$1}\"#{$2}\""
|
||||
end
|
||||
traverse = lambda do |node|
|
||||
case node
|
||||
when Psych::Nodes::Mapping
|
||||
children = node.children || []
|
||||
i = 0
|
||||
while i < children.length
|
||||
key = children[i]
|
||||
val = children[i + 1]
|
||||
if key.is_a?(Psych::Nodes::Scalar) && key.value == 'short-id'
|
||||
if val.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_scalar = (val.tag == 'tag:yaml.org,2002:null') || (val.tag == '!!null') || (val.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_scalar
|
||||
val.tag = nil
|
||||
val.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
elsif val.is_a?(Psych::Nodes::Sequence)
|
||||
val.children.each do |child|
|
||||
if child.is_a?(Psych::Nodes::Scalar)
|
||||
is_null_child = (child.tag == 'tag:yaml.org,2002:null') || (child.tag == '!!null') || (child.value =~ /^\s*(~|null|NULL|Null)\s*$/)
|
||||
unless is_null_child
|
||||
child.tag = nil
|
||||
child.style = defined?(Psych::Nodes::Scalar::DOUBLE_QUOTED) ? Psych::Nodes::Scalar::DOUBLE_QUOTED : 2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
traverse.call(key) if key.respond_to?(:children)
|
||||
traverse.call(val) if val.respond_to?(:children)
|
||||
end
|
||||
i += 2
|
||||
end
|
||||
when Psych::Nodes::Sequence
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
when Psych::Nodes::Document, Psych::Nodes::Stream
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
else
|
||||
if node.respond_to?(:children)
|
||||
(node.children || []).each { |c| traverse.call(c) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
lines = processed.lines
|
||||
short_id_indices = lines.each_index.select { |i| lines[i] =~ SHORT_ID_REGEX }
|
||||
short_id_indices.each do |short_id_index|
|
||||
line = lines[short_id_index]
|
||||
if line =~ SHORT_ID_REGEX
|
||||
indent = $1
|
||||
value = $2.strip
|
||||
if value.empty?
|
||||
(short_id_index + 1...lines.size).each do |i|
|
||||
line = lines[i]
|
||||
next if line.strip.empty?
|
||||
if line[/^\s*/].length <= short_id_indent_len
|
||||
break
|
||||
end
|
||||
if line =~ LIST_ITEM_REGEX
|
||||
indent = $1
|
||||
value = $2.strip
|
||||
if value =~ KEY_REGEX
|
||||
break
|
||||
end
|
||||
if value !~ QUOTED_VALUE_REGEX
|
||||
lines[i] = "#{indent}- \"#{value}\"\n"
|
||||
end
|
||||
elsif line =~ KEY_REGEX
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
if value !~ QUOTED_VALUE_REGEX
|
||||
lines[short_id_index] = "#{indent}short-id: \"#{value}\"\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
lines.join
|
||||
rescue => e
|
||||
LOG_ERROR("Fix short-id values type failed:【%s】" % [e.message])
|
||||
yaml_content
|
||||
end
|
||||
end
|
||||
end
|
||||
stream.children.each do |doc_node|
|
||||
if doc_node.is_a?(Psych::Nodes::Document)
|
||||
traverse.call(doc_node.root) if doc_node.root
|
||||
end
|
||||
end
|
||||
|
||||
if stream.respond_to?(:to_yaml)
|
||||
processed_yaml = stream.to_yaml
|
||||
processed_yaml = processed_yaml.gsub(/^([ \t]*short-id:\s*)!\s*/, "\\1")
|
||||
processed_yaml
|
||||
else
|
||||
yaml_content
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("Fix short-id values type failed:【%s】" % [e.message])
|
||||
yaml_content
|
||||
end
|
||||
end
|
||||
|
||||
def self.overwrite(base, override)
|
||||
return override if base.nil?
|
||||
return base if override.nil?
|
||||
|
||||
current_key = nil
|
||||
current_operation = nil
|
||||
|
||||
begin
|
||||
case override
|
||||
when Hash
|
||||
result = base.is_a?(Hash) ? base.dup : {}
|
||||
|
||||
override.each do |key, value|
|
||||
current_key = key
|
||||
processed_key, operation = parse_key(key)
|
||||
current_operation = operation
|
||||
|
||||
applied = apply_operation(result[processed_key], value, operation)
|
||||
if applied.equal?(DELETED_SENTINEL)
|
||||
result.delete(processed_key)
|
||||
else
|
||||
result[processed_key] = applied
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
override
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【key: %s, operation: %s, error: %s】" % [current_key, current_operation, e.message])
|
||||
base
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.parse_key(key)
|
||||
key_str = key.to_s
|
||||
|
||||
# +<key>
|
||||
if key_str.start_with?('+<') && key_str.include?('>')
|
||||
close_idx = key_str.index('>')
|
||||
inner_key = key_str[2...close_idx]
|
||||
return inner_key, :prepend_array
|
||||
end
|
||||
|
||||
# <key>suffix
|
||||
if key_str.start_with?('<') && key_str.include?('>')
|
||||
close_idx = key_str.index('>')
|
||||
inner_key = key_str[1...close_idx]
|
||||
suffix = key_str[(close_idx + 1)..-1]
|
||||
return inner_key, determine_operation(suffix)
|
||||
end
|
||||
|
||||
# 前缀 +key
|
||||
if key_str.start_with?('+')
|
||||
return key_str[1..-1], :prepend_array
|
||||
end
|
||||
|
||||
# 尾部(支持 +, !, *, -)
|
||||
if key_str =~ /^(.*?)([+!*\-])$/
|
||||
return Regexp.last_match(1), determine_operation(Regexp.last_match(2))
|
||||
end
|
||||
|
||||
[key_str, :merge]
|
||||
end
|
||||
|
||||
def self.determine_operation(suffix)
|
||||
case suffix
|
||||
when '+'
|
||||
:append_array
|
||||
when '-'
|
||||
:delete
|
||||
when '!'
|
||||
:force_overwrite
|
||||
when '*'
|
||||
:batch_update
|
||||
else
|
||||
:merge
|
||||
end
|
||||
end
|
||||
|
||||
def self.match_value(target, condition)
|
||||
return false if target.nil? || condition.nil?
|
||||
|
||||
begin
|
||||
if condition.is_a?(String) && condition.start_with?('/') && condition.end_with?('/')
|
||||
pattern = condition[1...-1]
|
||||
regexp = Regexp.new(pattern)
|
||||
if target.is_a?(Array)
|
||||
target.any? { |item| item.to_s =~ regexp }
|
||||
else
|
||||
target.to_s =~ regexp
|
||||
end
|
||||
elsif condition.is_a?(Array) && target.is_a?(Array)
|
||||
condition.all? { |c| target.include?(c) }
|
||||
else
|
||||
target == condition
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【(match value) => target: %s, condition: %s, error: %s】" % [target, condition, e.message])
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.deep_dup(obj)
|
||||
case obj
|
||||
when Array
|
||||
obj.map { |x| deep_dup(x) }
|
||||
when Hash
|
||||
obj.transform_values { |v| deep_dup(v) }
|
||||
else
|
||||
obj.dup rescue obj
|
||||
end
|
||||
end
|
||||
|
||||
def self.merge_hash(base, value, prepend: false)
|
||||
if prepend
|
||||
result = {}
|
||||
|
||||
value.each do |k, v|
|
||||
if base.key?(k)
|
||||
result[k] = apply_operation(base[k], v, :merge)
|
||||
else
|
||||
result[k] = deep_dup(v)
|
||||
end
|
||||
end
|
||||
|
||||
base.each do |k, v|
|
||||
result[k] = deep_dup(v) unless result.key?(k)
|
||||
end
|
||||
|
||||
result
|
||||
else
|
||||
result = deep_dup(base)
|
||||
|
||||
value.each do |k, v|
|
||||
if result.key?(k)
|
||||
result[k] = apply_operation(result[k], v, :merge)
|
||||
else
|
||||
result[k] = deep_dup(v)
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def self.delete_from_hash(base, value)
|
||||
result = deep_dup(base)
|
||||
|
||||
case value
|
||||
when Array
|
||||
value.each { |k| result.delete(k) }
|
||||
when Hash
|
||||
value.each do |k, v|
|
||||
if v.nil? || v == true
|
||||
result.delete(k)
|
||||
elsif result[k].is_a?(Hash) && v.is_a?(Hash)
|
||||
nested = apply_operation(result[k], v, :delete)
|
||||
if nested.equal?(DELETED_SENTINEL)
|
||||
result.delete(k)
|
||||
else
|
||||
result[k] = nested
|
||||
end
|
||||
else
|
||||
result.delete(k)
|
||||
end
|
||||
end
|
||||
else
|
||||
result.delete(value)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
DELETED_SENTINEL = Object.new.freeze
|
||||
|
||||
def self.apply_operation(base, value, operation)
|
||||
case operation
|
||||
when :delete
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
base - value
|
||||
elsif base.is_a?(Array) && !value.nil?
|
||||
base - [value]
|
||||
elsif base.is_a?(Hash)
|
||||
delete_from_hash(base, value)
|
||||
else
|
||||
DELETED_SENTINEL
|
||||
end
|
||||
when :force_overwrite
|
||||
deep_dup(value)
|
||||
when :prepend_array
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
(deep_dup(value) + base).uniq
|
||||
elsif base.is_a?(Hash) && value.is_a?(Hash)
|
||||
merge_hash(base, value, prepend: true)
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
when :append_array
|
||||
if base.is_a?(Array) && value.is_a?(Array)
|
||||
base_dup = base.dup
|
||||
deep_dup(value).each { |v| base_dup.delete(v) }
|
||||
base_dup + deep_dup(value)
|
||||
elsif base.is_a?(Hash) && value.is_a?(Hash)
|
||||
merge_hash(base, value, prepend: false)
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
when :batch_update
|
||||
batch_update_items(base, value)
|
||||
when :merge
|
||||
if base.is_a?(Hash) && value.is_a?(Hash)
|
||||
overwrite(base, value)
|
||||
elsif value.nil?
|
||||
base
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
else
|
||||
deep_dup(value)
|
||||
end
|
||||
end
|
||||
|
||||
def self.apply_set_fields(item, set_values)
|
||||
keys_to_delete = []
|
||||
|
||||
set_values.each do |k, v|
|
||||
processed_key, operation = parse_key(k)
|
||||
result = apply_operation(item[processed_key], v, operation)
|
||||
if result.equal?(DELETED_SENTINEL)
|
||||
keys_to_delete << processed_key
|
||||
else
|
||||
item[processed_key] = result
|
||||
end
|
||||
end
|
||||
|
||||
keys_to_delete.each { |k| item.delete(k) }
|
||||
end
|
||||
|
||||
def self.match_item(item, where_conditions, key = nil)
|
||||
where_conditions.all? do |k, v|
|
||||
if k == 'key' && !key.nil?
|
||||
match_value(key, v)
|
||||
elsif item.is_a?(Hash)
|
||||
match_value(item[k] || item[k.to_s], v)
|
||||
elsif item.is_a?(String) && k == 'value'
|
||||
match_value(item, v)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.batch_update_items(collection, update_spec)
|
||||
return collection unless update_spec.is_a?(Hash)
|
||||
|
||||
begin
|
||||
where_conditions = update_spec['where'] || {}
|
||||
set_values = update_spec['set'] || {}
|
||||
|
||||
if collection.is_a?(Array)
|
||||
result = collection.dup
|
||||
delete_indices = []
|
||||
|
||||
result.each_with_index do |item, index|
|
||||
match = match_item(item, where_conditions)
|
||||
|
||||
if match
|
||||
if item.is_a?(Hash)
|
||||
apply_set_fields(item, set_values)
|
||||
elsif item.is_a?(String) && set_values.key?('value')
|
||||
new_value = set_values['value']
|
||||
if new_value.nil?
|
||||
delete_indices << index
|
||||
else
|
||||
result[index] = deep_dup(new_value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
delete_indices.reverse_each { |i| result.delete_at(i) }
|
||||
result
|
||||
elsif collection.is_a?(Hash)
|
||||
if where_conditions.any? { |k, _| k != 'key' } &&
|
||||
match_item(collection, where_conditions)
|
||||
result = collection.dup
|
||||
apply_set_fields(result, set_values)
|
||||
result
|
||||
else
|
||||
result = collection.dup
|
||||
keys_to_delete = []
|
||||
|
||||
result.each do |key, value|
|
||||
next unless value.is_a?(Hash)
|
||||
match = match_item(value, where_conditions, key)
|
||||
|
||||
if match
|
||||
if set_values.key?('key-') || (set_values.key?('key') && set_values['key'].nil?)
|
||||
keys_to_delete << key
|
||||
else
|
||||
apply_set_fields(value, set_values)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
keys_to_delete.each { |k| result.delete(k) }
|
||||
result
|
||||
end
|
||||
elsif collection.nil?
|
||||
nil
|
||||
else
|
||||
collection
|
||||
end
|
||||
rescue => e
|
||||
LOG_ERROR("YAML overwrite failed:【(batch update) => update_spec: %s, error: %s】" % [update_spec, e.message])
|
||||
collection
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -86,17 +86,6 @@ DOWNLOAD_RESULT=$?
|
||||
|
||||
config_cus_up()
|
||||
{
|
||||
if [ -z "$CONFIG_PATH" ]; then
|
||||
for file_name in /etc/openclash/config/*
|
||||
do
|
||||
if [ -f "$file_name" ]; then
|
||||
CONFIG_PATH=$file_name
|
||||
break
|
||||
fi
|
||||
done
|
||||
uci -q set openclash.config.config_path="$CONFIG_PATH"
|
||||
uci commit openclash
|
||||
fi
|
||||
if [ -z "$subscribe_url_param" ]; then
|
||||
if [ -n "$key_match_param" ] || [ -n "$key_ex_match_param" ]; then
|
||||
LOG_OUT "Config File【$name】Start Picking Nodes..."
|
||||
@@ -192,6 +181,10 @@ config_su_check()
|
||||
mv "$CFG_FILE" "$CONFIG_FILE" 2>/dev/null
|
||||
LOG_OUT "Config File【$name】Update Successful!"
|
||||
fi
|
||||
if [ -z "$CONFIG_PATH" ]; then
|
||||
uci -q set openclash.config.config_path="$CONFIG_FILE"
|
||||
uci commit openclash
|
||||
fi
|
||||
if [ "$CONFIG_FILE" == "$CONFIG_PATH" ]; then
|
||||
restart=1
|
||||
fi
|
||||
@@ -335,13 +328,13 @@ sub_info_get()
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "sort" "$section" "sort" ""
|
||||
config_get "convert_address" "$section" "convert_address" ""
|
||||
config_get "convert_address" "$section" "convert_address" "https://api.asailor.org/sub"
|
||||
config_get "template" "$section" "template" ""
|
||||
config_get "node_type" "$section" "node_type" ""
|
||||
config_get "rule_provider" "$section" "rule_provider" ""
|
||||
config_get "custom_template_url" "$section" "custom_template_url" ""
|
||||
config_get "de_ex_keyword" "$section" "de_ex_keyword" ""
|
||||
config_get "sub_ua" "$section" "sub_ua" "clash.meta"
|
||||
config_get "sub_ua" "$section" "sub_ua" "clash-verge/v2.4.5"
|
||||
|
||||
CONFIG_FILE="/etc/openclash/config/$name.yaml"
|
||||
CFG_FILE="/tmp/$name.yaml"
|
||||
|
||||
@@ -74,7 +74,7 @@ DOWNLOAD_FILE_CURL() {
|
||||
fi
|
||||
else
|
||||
CURL_OUTPUT=$(curl -w "\n%{http_code}" -SsL --connect-timeout 30 -m 60 --speed-time 30 --speed-limit 1 --retry 2 -H "User-Agent: ${DOWNLOAD_UA}" "$DOWNLOAD_URL" -o "$DOWNLOAD_PATH" 2>&1)
|
||||
EXIR_CODE=${PIPESTATUS[0]}
|
||||
EXIR_CODE=$?
|
||||
HTTP_CODE=$(echo "$CURL_OUTPUT" | tail -n1)
|
||||
|
||||
if [ "$EXIR_CODE" -ne 0 ] || [ "$HTTP_CODE" -ne 200 ]; then
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 888>"/tmp/lock/openclash_update_databases.lock" 2>/dev/null
|
||||
flock -x 888 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 888 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_update_databases.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
update_one() {
|
||||
local type="$1"
|
||||
local custom_key="$2"
|
||||
local tmpfile="$3"
|
||||
local path="$4"
|
||||
local name="$5"
|
||||
local min_size=10240
|
||||
local download_url=""
|
||||
|
||||
local custom_url=$(uci_get_config "$custom_key")
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
|
||||
case "$type" in
|
||||
geoip)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
geosite)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
geoasn)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
|
||||
else
|
||||
download_url="${github_address_mod}https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
ipdb)
|
||||
if [ -z "$custom_url" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
download_url="${github_address_mod}gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
|
||||
else
|
||||
download_url="${github_address_mod}https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
download_url="$custom_url"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
LOG_OUT "【$name】Start Downloading Database..."
|
||||
|
||||
DOWNLOAD_FILE_CURL "$download_url" "/tmp/$tmpfile" "$path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/$tmpfile" ]; then
|
||||
if head -c 512 "/tmp/$tmpfile" | grep -qiE "<!doctype|<html|<head|<body"; then
|
||||
LOG_OUT "【$name】Download Failed: HTML Response Detected, Abort Update..."
|
||||
rm -rf "/tmp/$tmpfile"
|
||||
elif [ $(du -b "/tmp/$tmpfile" 2>/dev/null | awk '{print $1}' || echo "$min_size") -lt "$min_size" ]; then
|
||||
LOG_OUT "【$name】Download Failed: File Size Too Small, Abort Update..."
|
||||
rm -rf "/tmp/$tmpfile"
|
||||
else
|
||||
LOG_OUT "【$name】Download Success, Check Updated..."
|
||||
cmp -s "/tmp/$tmpfile" "$path"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
LOG_OUT "【$name】Has Been Updated, Starting To Replace The Old Version..."
|
||||
case "$type" in
|
||||
geoip)
|
||||
rm -rf "/etc/openclash/geoip.dat"
|
||||
;;
|
||||
geosite)
|
||||
rm -rf "/etc/openclash/geosite.dat"
|
||||
;;
|
||||
geoasn)
|
||||
rm -rf "/etc/openclash/GeoLite2-ASN.mmdb"
|
||||
;;
|
||||
esac
|
||||
mv "/tmp/$tmpfile" "$path" >/dev/null 2>&1
|
||||
LOG_OUT "【$name】Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "【$name】No Change, Do Nothing..."
|
||||
fi
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "【$name】No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "【$name】Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf "/tmp/$tmpfile" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
all)
|
||||
update_one geoip "geoip_custom_url" "GeoIP.dat" "/etc/openclash/GeoIP.dat" "GeoIP.dat"
|
||||
update_one geosite "geosite_custom_url" "GeoSite.dat" "/etc/openclash/GeoSite.dat" "GeoSite.dat"
|
||||
update_one geoasn "geoasn_custom_url" "GeoLite2-ASN.mmdb" "/etc/openclash/ASN.mmdb" "ASN.mmdb"
|
||||
update_one ipdb "geo_custom_url" "Country.mmdb" "/etc/openclash/Country.mmdb" "Country.mmdb"
|
||||
;;
|
||||
geoip)
|
||||
update_one geoip "geoip_custom_url" "GeoIP.dat" "/etc/openclash/GeoIP.dat" "GeoIP.dat"
|
||||
;;
|
||||
geosite)
|
||||
update_one geosite "geosite_custom_url" "GeoSite.dat" "/etc/openclash/GeoSite.dat" "GeoSite.dat"
|
||||
;;
|
||||
geoasn)
|
||||
update_one geoasn "geoasn_custom_url" "GeoLite2-ASN.mmdb" "/etc/openclash/ASN.mmdb" "ASN.mmdb"
|
||||
;;
|
||||
ipdb)
|
||||
update_one ipdb "geo_custom_url" "Country.mmdb" "/etc/openclash/Country.mmdb" "Country.mmdb"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {all|geoip|geosite|geoasn|ipdb}"
|
||||
del_lock
|
||||
dec_job_counter_and_restart "$restart"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 874>"/tmp/lock/openclash_geoasn.lock" 2>/dev/null
|
||||
flock -x 874 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 874 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geoasn.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOASN_CUSTOM_URL=$(uci_get_config "geoasn_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoasn_path="/etc/openclash/ASN.mmdb"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoasn_path="/tmp/etc/openclash/ASN.mmdb"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading Geo ASN Database..."
|
||||
if [ -z "$GEOASN_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/xishang0128/geoip@release/GeoLite2-ASN.mmdb"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/xishang0128/geoip/releases/latest/download/GeoLite2-ASN.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOASN_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoLite2-ASN.mmdb" "$geoasn_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoLite2-ASN.mmdb" ]; then
|
||||
LOG_OUT "Geo ASN Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoLite2-ASN.mmdb "$geoasn_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "Geo ASN Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/GeoLite2-ASN.mmdb"
|
||||
mv /tmp/GeoLite2-ASN.mmdb "$geoasn_path" >/dev/null 2>&1
|
||||
LOG_OUT "Geo ASN Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated Geo ASN Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated Geo ASN Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "Geo ASN Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoLite2-ASN.mmdb >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 873>"/tmp/lock/openclash_geoip.lock" 2>/dev/null
|
||||
flock -x 873 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 873 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geoip.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOIP_CUSTOM_URL=$(uci_get_config "geoip_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoip_path="/etc/openclash/GeoIP.dat"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoip_path="/tmp/etc/openclash/GeoIP.dat"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading GeoIP Dat..."
|
||||
if [ -z "$GEOIP_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOIP_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoIP.dat" "$geoip_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoIP.dat" ]; then
|
||||
LOG_OUT "GeoIP Dat Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoIP.dat "$geoip_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "GeoIP Dat Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/geoip.dat"
|
||||
mv /tmp/GeoIP.dat "$geoip_path" >/dev/null 2>&1
|
||||
LOG_OUT "GeoIP Dat Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated GeoIP Dat No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated GeoIP Dat No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "GeoIP Dat Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoIP.dat >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,70 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 874>"/tmp/lock/openclash_geosite.lock" 2>/dev/null
|
||||
flock -x 874 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 874 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_geosite.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOSITE_CUSTOM_URL=$(uci_get_config "geosite_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geosite_path="/etc/openclash/GeoSite.dat"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geosite_path="/tmp/etc/openclash/GeoSite.dat"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading GeoSite Database..."
|
||||
if [ -z "$GEOSITE_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOSITE_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/GeoSite.dat" "$geosite_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/GeoSite.dat" ]; then
|
||||
LOG_OUT "GeoSite Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/GeoSite.dat "$geosite_path"
|
||||
if [ "$?" -ne "0" ]; then
|
||||
LOG_OUT "GeoSite Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
rm -rf "/etc/openclash/geosite.dat"
|
||||
mv /tmp/GeoSite.dat "$geosite_path" >/dev/null 2>&1
|
||||
LOG_OUT "GeoSite Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated GeoSite Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated GeoSite Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "GeoSite Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/GeoSite.dat >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_curl.sh
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
set_lock() {
|
||||
exec 880>"/tmp/lock/openclash_ipdb.lock" 2>/dev/null
|
||||
flock -x 880 2>/dev/null
|
||||
}
|
||||
|
||||
del_lock() {
|
||||
flock -u 880 2>/dev/null
|
||||
rm -rf "/tmp/lock/openclash_ipdb.lock" 2>/dev/null
|
||||
}
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
|
||||
small_flash_memory=$(uci_get_config "small_flash_memory")
|
||||
GEOIP_CUSTOM_URL=$(uci_get_config "geo_custom_url")
|
||||
github_address_mod=$(uci_get_config "github_address_mod" || echo 0)
|
||||
restart=0
|
||||
|
||||
if [ "$small_flash_memory" != "1" ]; then
|
||||
geoip_path="/etc/openclash/Country.mmdb"
|
||||
mkdir -p /etc/openclash
|
||||
else
|
||||
geoip_path="/tmp/etc/openclash/Country.mmdb"
|
||||
mkdir -p /tmp/etc/openclash
|
||||
fi
|
||||
LOG_OUT "Start Downloading Geoip Database..."
|
||||
if [ -z "$GEOIP_CUSTOM_URL" ]; then
|
||||
if [ "$github_address_mod" != "0" ]; then
|
||||
if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then
|
||||
DOWNLOAD_URL="${github_address_mod}gh/alecthw/mmdb_china_ip_list@release/lite/Country.mmdb"
|
||||
else
|
||||
DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL="https://raw.githubusercontent.com/alecthw/mmdb_china_ip_list/release/lite/Country.mmdb"
|
||||
fi
|
||||
else
|
||||
DOWNLOAD_URL=$GEOIP_CUSTOM_URL
|
||||
fi
|
||||
DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "/tmp/Country.mmdb" "$geoip_path"
|
||||
DOWNLOAD_RESULT=$?
|
||||
if [ "$DOWNLOAD_RESULT" -eq 0 ] && [ -s "/tmp/Country.mmdb" ]; then
|
||||
LOG_OUT "Geoip Database Download Success, Check Updated..."
|
||||
cmp -s /tmp/Country.mmdb "$geoip_path"
|
||||
if [ "$?" -ne 0 ]; then
|
||||
LOG_OUT "Geoip Database Has Been Updated, Starting To Replace The Old Version..."
|
||||
mv /tmp/Country.mmdb "$geoip_path" >/dev/null 2>&1
|
||||
LOG_OUT "Geoip Database Update Successful!"
|
||||
restart=1
|
||||
else
|
||||
LOG_OUT "Updated Geoip Database No Change, Do Nothing..."
|
||||
fi
|
||||
elif [ "$DOWNLOAD_RESULT" -eq 2 ]; then
|
||||
LOG_OUT "Updated Geoip Database No Change, Do Nothing..."
|
||||
else
|
||||
LOG_OUT "Geoip Database Update Error, Please Try Again Later..."
|
||||
fi
|
||||
|
||||
rm -rf /tmp/Country.mmdb >/dev/null 2>&1
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
@@ -46,7 +46,7 @@ function unlock_auto_select()
|
||||
local no_old_region_unlock = {}
|
||||
local full_support_list = {}
|
||||
local fallback_select = {}
|
||||
local gorup_i18 = "Group:"
|
||||
local gorup_i18 = "【"..type.."】Group:"
|
||||
local no_group_find = "failed to search based on keywords and automatically obtain the group, please confirm the validity of the regex!"
|
||||
local full_support_no_area = "full support"
|
||||
local full_support = "full support, area:"
|
||||
@@ -119,6 +119,10 @@ function unlock_auto_select()
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_google_not_cn") or "google|谷歌"
|
||||
elseif type == "OpenAI" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_openai") or "OpenAI|ChatGPT"
|
||||
elseif type == "Claude" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_claude") or "Claude"
|
||||
elseif type == "Gemini" then
|
||||
key_group = FS.uci_get_config("config", "stream_auto_select_group_key_gemini") or "Gemini"
|
||||
end
|
||||
if not key_group then key_group = type end
|
||||
else
|
||||
@@ -148,9 +152,9 @@ function unlock_auto_select()
|
||||
--test now proxy
|
||||
region = proxy_unlock_test()
|
||||
if table_include(groups, now_name) then
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
end
|
||||
if status ~= 2 and status ~= 4 then
|
||||
region = proxy_unlock_test()
|
||||
@@ -244,7 +248,7 @@ function unlock_auto_select()
|
||||
end
|
||||
end
|
||||
if #(value.all) == 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..no_nodes_filter)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..no_nodes_filter)
|
||||
break
|
||||
end
|
||||
--loop proxy test
|
||||
@@ -274,16 +278,16 @@ function unlock_auto_select()
|
||||
end
|
||||
end
|
||||
if #(proxies) == 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"..no_nodes_filter)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"..no_nodes_filter)
|
||||
break
|
||||
end
|
||||
for p = 1, #(proxies) do
|
||||
proxy = proxies[p]
|
||||
if table_include(groups, proxy) then
|
||||
group_now = get_group_now(info, proxy)
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..group_now.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..group_now.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..proxy.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..proxy.."】"
|
||||
end
|
||||
--skip tested proxy
|
||||
while true do
|
||||
@@ -303,7 +307,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, proxy, region})
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
@@ -312,7 +316,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, proxy})
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..proxy.."】")
|
||||
else
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
@@ -372,16 +376,16 @@ function unlock_auto_select()
|
||||
end
|
||||
region = proxy_unlock_test()
|
||||
if table_include(groups, now_name) then
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.."】"
|
||||
else
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
now = os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..group_show.." ➟ "..now_name.."】"
|
||||
end
|
||||
if status == 2 then
|
||||
if region ~= "" then
|
||||
table.insert(full_support_list, {value.all[i], group_name, value.all[i], region})
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
@@ -390,7 +394,7 @@ function unlock_auto_select()
|
||||
table.insert(full_support_list, {value.all[i], group_name, value.all[i]})
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, now_name).."】")
|
||||
else
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
@@ -469,24 +473,24 @@ function unlock_auto_select()
|
||||
group_now = group_now .. area_i18 .. "【"..v[4].."】"
|
||||
end
|
||||
if #full_support_list > 0 then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_full_support..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_full_support..group_now)
|
||||
elseif #no_old_region_unlock > 0 then
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success_no_old_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success_no_old_region..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_no_old_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_no_old_region..group_now)
|
||||
end
|
||||
elseif #other_region_unlock > 0 then
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild_other_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild_other_region..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_other_region..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_other_region..group_now)
|
||||
end
|
||||
else
|
||||
if not all_test then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild..group_now)
|
||||
else
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_all_faild..group_now)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_all_faild..group_now)
|
||||
end
|
||||
end
|
||||
close_connections()
|
||||
@@ -499,7 +503,7 @@ function unlock_auto_select()
|
||||
else
|
||||
group_now = value.name.." ➟ "..proxy_default
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_faild.."【"..group_now.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_faild.."【"..group_now.."】")
|
||||
end
|
||||
end
|
||||
elseif #nodes_filter(get_group_now(info, value.name), info) ~= 0 then
|
||||
@@ -509,12 +513,12 @@ function unlock_auto_select()
|
||||
if not all_test then
|
||||
print(now..full_support.."【"..region.."】")
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】"..area_i18.."【"..region.."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】"..area_i18.."【"..region.."】")
|
||||
else
|
||||
if not all_test then
|
||||
print(now..full_support_no_area)
|
||||
end
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】")
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..value.name.."】"..select_success.."【"..get_group_now(info, value.name).."】")
|
||||
end
|
||||
if not all_test then
|
||||
break
|
||||
@@ -548,7 +552,7 @@ function unlock_auto_select()
|
||||
if status == 2 and not all_test then break end
|
||||
end
|
||||
if not group_match and not auto_get_group then
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..type.." "..gorup_i18.."【"..key_group.."】"..no_group_find)
|
||||
print(os.date("%Y-%m-%d %H:%M:%S").." [Info] "..gorup_i18.."【"..key_group.."】"..no_group_find)
|
||||
end
|
||||
--write cache
|
||||
FS.writefile(unlock_cache_file, JSON.stringify(unlock_cache_info))
|
||||
@@ -817,6 +821,10 @@ function nodes_filter(t, info)
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_google_not_cn") or ""
|
||||
elseif type == "OpenAI" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_openai") or ""
|
||||
elseif type == "Claude" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_claude") or ""
|
||||
elseif type == "Gemini" then
|
||||
regex = FS.uci_get_config("config", "stream_auto_select_node_key_gemini") or ""
|
||||
end
|
||||
|
||||
if class_type(t) == "table" then
|
||||
@@ -877,6 +885,10 @@ function proxy_unlock_test()
|
||||
region = google_not_cn_test()
|
||||
elseif type == "OpenAI" then
|
||||
region = openai_unlock_test()
|
||||
elseif type == "Claude" then
|
||||
region = claude_unlock_test()
|
||||
elseif type == "Gemini" then
|
||||
region = gemini_unlock_test()
|
||||
end
|
||||
return region
|
||||
end
|
||||
@@ -908,6 +920,10 @@ function auto_get_policy_group(passwd, ip, port)
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://timeline.google.com &')
|
||||
elseif type == "OpenAI" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://chatgpt.com/ &')
|
||||
elseif type == "Claude" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://claude.ai/ &')
|
||||
elseif type == "Gemini" then
|
||||
SYS.call('curl -sL -m 5 --limit-rate 1k -o /dev/null https://gemini.google.com/ &')
|
||||
end
|
||||
os.execute("sleep 1")
|
||||
con = SYS.exec(string.format('curl -sL -m 5 --retry 2 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XGET http://%s:%s/connections', passwd, ip, port))
|
||||
@@ -976,6 +992,16 @@ function auto_get_policy_group(passwd, ip, port)
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
elseif type == "Claude" then
|
||||
if string.match(con.connections[i].metadata.host, "claude%.ai") then
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
elseif type == "Gemini" then
|
||||
if string.match(con.connections[i].metadata.host, "gemini%.google%.com") then
|
||||
auto_get_group = con.connections[i].chains[#(con.connections[i].chains)]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1571,6 +1597,82 @@ function openai_unlock_test()
|
||||
return region
|
||||
end
|
||||
|
||||
function claude_unlock_test()
|
||||
status = 0
|
||||
local url = "https://claude.ai/"
|
||||
local region_url = "https://claude.ai/cdn-cgi/trace"
|
||||
local regex = FS.uci_get_config("config", "stream_auto_select_region_key_claude") or ""
|
||||
local region = ""
|
||||
local old_region = get_old_region()
|
||||
local old_regex = get_old_regex()
|
||||
local data = SYS.exec(string.format("curl -sIL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, url))
|
||||
if data then
|
||||
if string.find(data, "App unavailable in region") then
|
||||
status = 1
|
||||
else
|
||||
status = 2
|
||||
local region_data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, region_url))
|
||||
if region_data and string.match(region_data, "loc=%a+") then
|
||||
region = string.upper(string.sub(string.match(region_data, "loc=%a+"), 5, -1))
|
||||
if not datamatch(region, regex) then
|
||||
status = 3
|
||||
elseif old_regex ~= regex and not all_test then
|
||||
status = 2
|
||||
elseif old_region ~= "" and region ~= old_region and not all_test then
|
||||
status = 4
|
||||
end
|
||||
if status == 2 and not all_test and region ~= old_region then
|
||||
write_cache(type, "old_region", region)
|
||||
end
|
||||
if status == 2 and not all_test and regex ~= old_regex then
|
||||
write_cache(type, "old_regex", regex)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return region
|
||||
end
|
||||
|
||||
function gemini_unlock_test()
|
||||
status = 0
|
||||
local url = "https://gemini.google.com/"
|
||||
local regex = FS.uci_get_config("config", "stream_auto_select_region_key_gemini") or ""
|
||||
local region = ""
|
||||
local old_region = get_old_region()
|
||||
local old_regex = get_old_regex()
|
||||
local data = SYS.exec(string.format("curl -sL --connect-timeout 5 -m 5 --speed-time 5 --speed-limit 1 --retry 2 -H 'Accept-Language: en' -H 'Content-Type: application/json' -H 'User-Agent: %s' '%s'", UA, url))
|
||||
if not data or string.sub(data, 1, 4) == "curl" then
|
||||
status = 1
|
||||
return region
|
||||
end
|
||||
|
||||
if string.find(data, "45631641,null,true", 1, true) then
|
||||
local cc = string.match(data, ',2,1,200,"([A-Z][A-Z][A-Z])"')
|
||||
if cc and cc ~= "" then
|
||||
region = cc
|
||||
end
|
||||
status = 2
|
||||
if region ~= "" then
|
||||
if not datamatch(region, regex) then
|
||||
status = 3
|
||||
elseif old_regex ~= regex and not all_test then
|
||||
status = 2
|
||||
elseif old_region ~= "" and region ~= old_region and not all_test then
|
||||
status = 4
|
||||
end
|
||||
if status == 2 and not all_test and region ~= old_region then
|
||||
write_cache(type, "old_region", region)
|
||||
end
|
||||
if status == 2 and not all_test and regex ~= old_regex then
|
||||
write_cache(type, "old_regex", regex)
|
||||
end
|
||||
end
|
||||
else
|
||||
status = 1
|
||||
end
|
||||
return region
|
||||
end
|
||||
|
||||
function network_test()
|
||||
local test_url1 = "https://www.gstatic.com/generate_204"
|
||||
local test_url2 = "https://cp.cloudflare.com/generate_204"
|
||||
|
||||
@@ -16,7 +16,6 @@ del_lock() {
|
||||
|
||||
set_lock
|
||||
inc_job_counter
|
||||
restart=0
|
||||
|
||||
if [ -n "$1" ] && [ "$1" != "one_key_update" ]; then
|
||||
/usr/share/openclash/openclash_version.sh "$1" 2>/dev/null
|
||||
@@ -29,7 +28,7 @@ fi
|
||||
if [ ! -f "/tmp/openclash_last_version" ]; then
|
||||
LOG_ERROR "Failed to get version information, please try again later..."
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -57,7 +56,7 @@ LAST_VER=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
OP_CV=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
OP_CV=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
OP_CV=$(apk list luci-app-openclash 2>/dev/null|grep "installed" | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
OP_LV=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n")
|
||||
RELEASE_BRANCH=$(uci_get_config "release_branch" || echo "master")
|
||||
@@ -69,14 +68,12 @@ if [ "$1" = "one_key_update" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
fi
|
||||
if [ -n "$2" ]; then
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1 &
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1
|
||||
github_address_mod="$2"
|
||||
else
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1 &
|
||||
/usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1
|
||||
github_address_mod=0
|
||||
fi
|
||||
|
||||
wait
|
||||
else
|
||||
if [ "$github_address_mod" = "0" ]; then
|
||||
LOG_TIP "If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options"
|
||||
@@ -175,9 +172,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
dec_job_counter_and_restart "0"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -191,8 +187,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
LOG_ERROR "【OpenClash - v$LAST_VER】Download Failed after 3 attempts, please check the network or try again later!"
|
||||
rm -rf /tmp/openclash.ipk >/dev/null 2>&1
|
||||
rm -rf /tmp/openclash.apk >/dev/null 2>&1
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
del_lock
|
||||
exit 0
|
||||
fi
|
||||
@@ -200,9 +196,8 @@ if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [
|
||||
done
|
||||
cat > /tmp/openclash_update.sh <<"EOF"
|
||||
#!/bin/sh
|
||||
START_LOG="/tmp/openclash_start.log"
|
||||
LOG_FILE="/tmp/openclash.log"
|
||||
LOGTIME=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
. /usr/share/openclash/log.sh
|
||||
. /usr/share/openclash/openclash_ps.sh
|
||||
|
||||
UPDATE_LOCK="/tmp/lock/openclash_update_install.lock"
|
||||
mkdir -p /tmp/lock
|
||||
@@ -224,27 +219,6 @@ fi
|
||||
|
||||
trap 'del_update_lock; exit' INT TERM EXIT
|
||||
|
||||
LOG_ERROR()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "${LOGTIME} [Error] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
LOG_TIP()
|
||||
{
|
||||
if [ -n "${1}" ]; then
|
||||
echo -e "${1}" > $START_LOG
|
||||
echo -e "${LOGTIME} [Tip] ${1}" >> $LOG_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
SLOG_CLEAN()
|
||||
{
|
||||
echo "" > $START_LOG
|
||||
}
|
||||
|
||||
check_install_success()
|
||||
{
|
||||
local target_version="$1"
|
||||
@@ -253,7 +227,7 @@ check_install_success()
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
current_version=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null)
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
current_version=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
current_version=$(apk list luci-app-openclash 2>/dev/null |grep "installed" | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null)
|
||||
fi
|
||||
|
||||
if [ -n "$current_version" ] && [ "$current_version" = "$target_version" ]; then
|
||||
@@ -266,41 +240,39 @@ check_install_success()
|
||||
install_missing_packages() {
|
||||
local installed_before="$1"
|
||||
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
if [ -n "$installed_before" ]; then
|
||||
for pkg in $installed_before; do
|
||||
if ! opkg status "$pkg" >/dev/null 2>&1; then
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
if opkg status "$pkg" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
if apk list "$pkg" |grep "installed" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
LOG_TIP "【$pkg】depended package reinstalling..."
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ -x "/bin/opkg" ]; then
|
||||
opkg install "$pkg"
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
for pkg in $installed_before; do
|
||||
if ! apk info "$pkg" >/dev/null 2>&1; then
|
||||
local retry_count=0
|
||||
local max_retries=3
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
retry_count=$((retry_count + 1))
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
apk add "$pkg"
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
fi
|
||||
if [ $? -eq 0 ]; then
|
||||
break
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
else
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
sleep 2
|
||||
fi
|
||||
LOG_ERROR "【$pkg】failed to install, please try to install it manually..."
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
fi
|
||||
}
|
||||
@@ -324,7 +296,7 @@ while [ $install_retry_count -lt $max_install_retries ]; do
|
||||
opkg install /tmp/openclash.ipk
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
for pkg in $packages_to_check; do
|
||||
if apk info "$pkg" >/dev/null 2>&1; then
|
||||
if apk list "$pkg" |grep "installed" >/dev/null 2>&1; then
|
||||
installed_before="$installed_before $pkg"
|
||||
fi
|
||||
done
|
||||
@@ -357,9 +329,9 @@ else
|
||||
elif [ -x "/usr/bin/apk" ]; then
|
||||
LOG_ERROR "OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】"
|
||||
fi
|
||||
SLOG_CLEAN
|
||||
fi
|
||||
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_update_lock
|
||||
EOF
|
||||
chmod 4755 /tmp/openclash_update.sh
|
||||
@@ -367,6 +339,8 @@ EOF
|
||||
if [ ! -f "/tmp/openclash_update.sh" ] || [ ! -s "/tmp/openclash_update.sh" ] || [ ! -x "/tmp/openclash_update.sh" ]; then
|
||||
LOG_ERROR "Failed to create update script!"
|
||||
rm -rf /tmp/openclash_update.sh
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
del_lock
|
||||
exit 1
|
||||
fi
|
||||
@@ -405,8 +379,8 @@ else
|
||||
else
|
||||
LOG_TIP "OpenClash has not been updated, stop continuing!"
|
||||
fi
|
||||
dec_job_counter_and_restart "0"
|
||||
SLOG_CLEAN
|
||||
dec_job_counter_and_restart "$restart"
|
||||
fi
|
||||
|
||||
del_lock
|
||||
@@ -5,20 +5,10 @@
|
||||
. /usr/share/openclash/uci.sh
|
||||
|
||||
LOG_FILE="/tmp/openclash.log"
|
||||
CONFIG_FILE="/etc/openclash/$(uci_get_config "config_path" |awk -F '/' '{print $5}' 2>/dev/null)"
|
||||
ipv6_enable=$(uci_get_config "ipv6_enable" || echo 0)
|
||||
enable_redirect_dns=$(uci_get_config "enable_redirect_dns")
|
||||
dns_port=$(uci_get_config "dns_port")
|
||||
disable_masq_cache=$(uci_get_config "disable_masq_cache")
|
||||
cfg_update_interval=$(uci_get_config "config_update_interval" || echo 60)
|
||||
log_size=$(uci_get_config "log_size" || echo 1024)
|
||||
router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1)
|
||||
stream_auto_select_interval=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
skip_proxy_address=$(uci_get_config "skip_proxy_address" || echo 0)
|
||||
CFG_UPDATE_INT=1
|
||||
CFG_UPDATE_INT=0
|
||||
SKIP_PROXY_ADDRESS=1
|
||||
SKIP_PROXY_ADDRESS_INTERVAL=30
|
||||
STREAM_AUTO_SELECT=1
|
||||
STREAM_AUTO_SELECT=0
|
||||
FIREWALL_RELOAD=0
|
||||
MAX_FIREWALL_RELOAD=3
|
||||
FW4=$(command -v fw4)
|
||||
@@ -155,11 +145,20 @@ end" 2>/dev/null >> $LOG_FILE
|
||||
|
||||
while :;
|
||||
do
|
||||
CONFIG_FILE="/etc/openclash/$(uci_get_config "config_path" |awk -F '/' '{print $5}' 2>/dev/null)"
|
||||
ipv6_enable=$(uci_get_config "ipv6_enable" || echo 0)
|
||||
enable_redirect_dns=$(uci_get_config "enable_redirect_dns")
|
||||
dns_port=$(uci_get_config "dns_port")
|
||||
disable_masq_cache=$(uci_get_config "disable_masq_cache")
|
||||
log_size=$(uci_get_config "log_size" || echo 1024)
|
||||
router_self_proxy=$(uci_get_config "router_self_proxy" || echo 1)
|
||||
skip_proxy_address=$(uci_get_config "skip_proxy_address" || echo 0)
|
||||
|
||||
cfg_update=$(uci_get_config "auto_update")
|
||||
cfg_update_mode=$(uci_get_config "config_auto_update_mode")
|
||||
cfg_update_interval_now=$(uci_get_config "config_update_interval" || echo 60)
|
||||
cfg_update_interval=$(uci_get_config "config_update_interval" || echo 60)
|
||||
stream_auto_select=$(uci_get_config "stream_auto_select" || echo 0)
|
||||
stream_auto_select_interval_now=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
stream_auto_select_interval=$(uci_get_config "stream_auto_select_interval" || echo 30)
|
||||
stream_auto_select_netflix=$(uci_get_config "stream_auto_select_netflix" || echo 0)
|
||||
stream_auto_select_disney=$(uci_get_config "stream_auto_select_disney" || echo 0)
|
||||
stream_auto_select_hbo_max=$(uci_get_config "stream_auto_select_hbo_max" || echo 0)
|
||||
@@ -172,6 +171,8 @@ do
|
||||
stream_auto_select_bilibili=$(uci_get_config "stream_auto_select_bilibili" || echo 0)
|
||||
stream_auto_select_google_not_cn=$(uci_get_config "stream_auto_select_google_not_cn" || echo 0)
|
||||
stream_auto_select_openai=$(uci_get_config "stream_auto_select_openai" || echo 0)
|
||||
stream_auto_select_claude=$(uci_get_config "stream_auto_select_claude" || echo 0)
|
||||
stream_auto_select_gemini=$(uci_get_config "stream_auto_select_gemini" || echo 0)
|
||||
upnp_lease_file=$(uci -q get upnpd.config.upnp_lease_file)
|
||||
|
||||
#wait for core start complete
|
||||
@@ -362,66 +363,72 @@ fi
|
||||
|
||||
## 配置文件循环更新
|
||||
if [ "$cfg_update" -eq 1 ] && [ "$cfg_update_mode" -eq 1 ]; then
|
||||
[ "$cfg_update_interval" -ne "$cfg_update_interval_now" ] && CFG_UPDATE_INT=0 && cfg_update_interval="$cfg_update_interval_now"
|
||||
if [ "$CFG_UPDATE_INT" -ne 0 ]; then
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$cfg_update_interval_now")" -eq 0 ] && /usr/share/openclash/openclash.sh
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$cfg_update_interval")" -eq 0 ] && /usr/share/openclash/openclash.sh
|
||||
fi
|
||||
CFG_UPDATE_INT=$(expr "$CFG_UPDATE_INT" + 1)
|
||||
fi
|
||||
|
||||
##STREAMING_UNLOCK_CHECK
|
||||
if [ "$stream_auto_select" -eq 1 ] && [ "$router_self_proxy" -eq 1 ]; then
|
||||
[ "$stream_auto_select_interval" -ne "$stream_auto_select_interval_now" ] && STREAM_AUTO_SELECT=1 && stream_auto_select_interval="$stream_auto_select_interval_now"
|
||||
if [ "$STREAM_AUTO_SELECT" -ne 0 ]; then
|
||||
if [ "$(expr "$STREAM_AUTO_SELECT" % "$stream_auto_select_interval_now")" -eq 0 ] || [ "$STREAM_AUTO_SELECT" -eq 1 ]; then
|
||||
if [ "$(expr "$STREAM_AUTO_SELECT" % "$stream_auto_select_interval")" -eq 0 ] || [ "$STREAM_AUTO_SELECT" -eq 1 ]; then
|
||||
if [ "$stream_auto_select_netflix" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Netflix Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Netflix】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Netflix" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_disney" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Disney Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Disney Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Disney Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_google_not_cn" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Google Not CN Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Google Not CN】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Google" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_ytb" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For YouTube Premium Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【YouTube Premium】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "YouTube Premium" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_prime_video" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Amazon Prime Video Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Amazon Prime Video】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Amazon Prime Video" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_hbo_max" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For HBO Max Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【HBO Max】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "HBO Max" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_tvb_anywhere" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For TVB Anywhere+ Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【TVB Anywhere+】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "TVB Anywhere+" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_dazn" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For DAZN Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【DAZN】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "DAZN" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_paramount_plus" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Paramount Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Paramount Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Paramount Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_discovery_plus" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Discovery Plus Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Discovery Plus】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Discovery Plus" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_bilibili" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For Bilibili Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Bilibili】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Bilibili" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_openai" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Proxy For OpenAI Unlock..."
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【OpenAI】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "OpenAI" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_claude" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Claude】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Claude" >> $LOG_FILE
|
||||
fi
|
||||
if [ "$stream_auto_select_gemini" -eq 1 ]; then
|
||||
LOG_TIP "Start Auto Select Unlock Proxy For【Gemini】..."
|
||||
/usr/share/openclash/openclash_streaming_unlock.lua "Gemini" >> $LOG_FILE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
STREAM_AUTO_SELECT=$(expr "$STREAM_AUTO_SELECT" + 1)
|
||||
|
||||
@@ -672,6 +672,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "example"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
# ip-version: ipv4
|
||||
|
||||
# vless
|
||||
@@ -762,6 +763,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "grpc"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
|
||||
reality-opts:
|
||||
public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE
|
||||
@@ -790,6 +792,69 @@ proxies: # socks5
|
||||
# v2ray-http-upgrade: false
|
||||
# v2ray-http-upgrade-fast-open: false
|
||||
|
||||
- name: "vless-xhttp"
|
||||
type: vless
|
||||
server: server
|
||||
port: 443
|
||||
uuid: uuid
|
||||
udp: true
|
||||
tls: true
|
||||
network: xhttp
|
||||
alpn:
|
||||
- h2
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
# fingerprint: ...
|
||||
# certificate: ...
|
||||
# private-key: ...
|
||||
servername: xxx.com
|
||||
client-fingerprint: chrome
|
||||
encryption: ""
|
||||
xhttp-opts:
|
||||
path: "/"
|
||||
host: xxx.com
|
||||
# mode: "stream-one" # Available: "stream-one", "stream-up" or "packet-up"
|
||||
# headers:
|
||||
# X-Forwarded-For: ""
|
||||
# no-grpc-header: false
|
||||
# x-padding-bytes: "100-1000"
|
||||
# reuse-settings: # aka XMUX
|
||||
# max-connections: "16-32"
|
||||
# max-concurrency: "0"
|
||||
# c-max-reuse-times: "0"
|
||||
# h-max-request-times: "600-900"
|
||||
# h-max-reusable-secs: "1800-3000"
|
||||
# download-settings:
|
||||
# ## xhttp part
|
||||
# path: "/"
|
||||
# host: xxx.com
|
||||
# headers:
|
||||
# X-Forwarded-For: ""
|
||||
# no-grpc-header: false
|
||||
# x-padding-bytes: "100-1000"
|
||||
# reuse-settings: # aka XMUX
|
||||
# max-connections: "16-32"
|
||||
# max-concurrency: "0"
|
||||
# c-max-reuse-times: "0"
|
||||
# h-max-request-times: "600-900"
|
||||
# h-max-reusable-secs: "1800-3000"
|
||||
# ## proxy part
|
||||
# server: server
|
||||
# port: 443
|
||||
# tls: true
|
||||
# alpn:
|
||||
# - h2
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
# fingerprint: ...
|
||||
# certificate: ...
|
||||
# private-key: ...
|
||||
# servername: xxx.com
|
||||
# client-fingerprint: chrome
|
||||
|
||||
|
||||
# Trojan
|
||||
- name: "trojan"
|
||||
type: trojan
|
||||
@@ -833,6 +898,7 @@ proxies: # socks5
|
||||
grpc-opts:
|
||||
grpc-service-name: "example"
|
||||
# grpc-user-agent: "grpc-go/1.36.0"
|
||||
# ping-interval: 0 # 默认关闭,单位为秒
|
||||
|
||||
- name: trojan-ws
|
||||
server: server
|
||||
@@ -1080,6 +1146,8 @@ proxies: # socks5
|
||||
# multiplexing: MULTIPLEXING_LOW
|
||||
# 如果想开启 0-RTT 握手,请设置为 HANDSHAKE_NO_WAIT,否则请设置为 HANDSHAKE_STANDARD。默认值为 HANDSHAKE_STANDARD
|
||||
# handshake-mode: HANDSHAKE_STANDARD
|
||||
# 一个 base64 字符串用于微调网络行为
|
||||
# traffic-pattern: ""
|
||||
|
||||
# sudoku
|
||||
- name: sudoku
|
||||
@@ -1090,15 +1158,17 @@ proxies: # socks5
|
||||
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
|
||||
padding-min: 2 # 最小填充率(0-100)
|
||||
padding-max: 7 # 最大填充率(0-100,必须 >= padding-min)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table
|
||||
http-mask: true # 是否启用http掩码
|
||||
# http-mask-mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll);stream/poll/auto 支持走 CDN/反代
|
||||
# http-mask-tls: true # 可选:仅在 http-mask-mode 为 stream/poll/auto 时生效;true 强制 https;false 强制 http(不会根据端口自动推断)
|
||||
# http-mask-host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 http-mask-mode 为 stream/poll/auto 时生效
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload
|
||||
# http-mask-multiplex: off # 可选:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 http-mask-mode=stream/poll/auto 生效)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合;只对 entropy 方向生效
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),非空时覆盖 custom-table
|
||||
# 推荐:使用 httpmask 对象统一管理 HTTPMask 相关字段:
|
||||
httpmask:
|
||||
disable: false # true 禁用所有 HTTP 伪装/隧道
|
||||
mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道)
|
||||
# tls: true # 可选:按需开启 HTTPS/WSS
|
||||
# host: "" # 可选:覆盖 Host/SNI(支持 example.com 或 example.com:443);仅在 mode 为 stream/poll/auto/ws 时生效
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws
|
||||
# multiplex: "off" # 可选字符串:off(默认)、auto(复用底层 HTTP 连接,减少建链 RTT)、on(Sudoku mux 单隧道多目标;仅在 mode=stream/poll/auto 生效;ws 强制 off)
|
||||
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
|
||||
|
||||
# anytls
|
||||
@@ -1118,6 +1188,23 @@ proxies: # socks5
|
||||
# - http/1.1
|
||||
# skip-cert-verify: true
|
||||
|
||||
# trusttunnel
|
||||
- name: trusttunnel
|
||||
type: trusttunnel
|
||||
server: 1.2.3.4
|
||||
port: 443
|
||||
username: username
|
||||
password: password
|
||||
# client-fingerprint: chrome
|
||||
health-check: true
|
||||
udp: true
|
||||
# sni: "example.com"
|
||||
# alpn:
|
||||
# - h2
|
||||
# skip-cert-verify: true
|
||||
# quic: true # 默认为false
|
||||
# congestion-controller: bbr
|
||||
|
||||
# dns 出站会将请求劫持到内部 dns 模块,所有请求均在内部处理
|
||||
- name: "dns-out"
|
||||
type: dns
|
||||
@@ -1555,6 +1642,12 @@ listeners:
|
||||
flow: xtls-rprx-vision
|
||||
# ws-path: "/" # 如果不为空则开启 websocket 传输层
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# xhttp-config: # 如果不为空则开启 xhttp 传输层
|
||||
# path: "/"
|
||||
# host: ""
|
||||
# mode: auto # Available: "stream-one", "stream-up" or "packet-up"
|
||||
# no-sse-header: false
|
||||
# sc-stream-up-server-secs: "20-80"
|
||||
# -------------------------
|
||||
# vless encryption服务端配置:
|
||||
# (原生外观 / 只 XOR 公钥 / 全随机数。1-RTT 每次下发随机 300 到 600 秒的 ticket 以便 0-RTT 复用 / 只允许 1-RTT)
|
||||
@@ -1631,6 +1724,8 @@ listeners:
|
||||
users:
|
||||
username1: password1
|
||||
username2: password2
|
||||
# 一个 base64 字符串用于微调网络行为
|
||||
# traffic-pattern: ""
|
||||
|
||||
- name: sudoku-in-1
|
||||
type: sudoku
|
||||
@@ -1640,14 +1735,18 @@ listeners:
|
||||
aead-method: chacha20-poly1305 # 可选:chacha20-poly1305、aes-128-gcm、none(不建议;且 enable-pure-downlink=false 时不可用)
|
||||
padding-min: 1 # 最小填充率(0-100)
|
||||
padding-max: 15 # 最大填充率(0-100,必须 >= padding-min)
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy`
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table
|
||||
table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy、up_ascii_down_entropy、up_entropy_down_ascii
|
||||
# custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合;只对 entropy 方向生效
|
||||
# custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于多表轮换;非空时覆盖 custom-table
|
||||
handshake-timeout: 5 # 可选(秒)
|
||||
enable-pure-downlink: false # 可选:false=带宽优化下行(更快,要求 aead-method != none);true=纯 Sudoku 下行
|
||||
disable-http-mask: false # 可选:禁用 http 掩码/隧道(默认为 false)
|
||||
# http-mask-mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll);stream/poll/auto 支持走 CDN/反代
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload
|
||||
# 推荐:使用 httpmask 对象统一管理 HTTPMask 相关字段:
|
||||
httpmask:
|
||||
disable: false # true 禁用所有 HTTP 伪装/隧道
|
||||
mode: legacy # 可选:legacy(默认)、stream(split-stream)、poll、auto(先 stream 再 poll)、ws(WebSocket 隧道)
|
||||
# path-root: "" # 可选:HTTP 隧道端点一级路径前缀(双方需一致),例如 "aabbcc" 或 "/aabbcc/" => /aabbcc/session、/aabbcc/stream、/aabbcc/api/v1/upload、/aabbcc/ws
|
||||
#
|
||||
# fallback: "127.0.0.1:80" # 可选:用于可连接请求的回落转发,可与其他服务共端口
|
||||
|
||||
|
||||
|
||||
@@ -1734,6 +1833,30 @@ listeners:
|
||||
# masquerade: http://127.0.0.1:8080 #作为反向代理
|
||||
# masquerade: https://127.0.0.1:8080 #作为反向代理
|
||||
|
||||
- name: trusttunnel-in-1
|
||||
type: trusttunnel
|
||||
port: 10821 # 支持使用ports格式,例如200,302 or 200,204,401-429,501-503
|
||||
listen: 0.0.0.0
|
||||
# rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules
|
||||
# proxy: proxy # 如果不为空则直接将该入站流量交由指定 proxy 处理 (当 proxy 不为空时,这里的 proxy 名称必须合法,否则会出错)
|
||||
users:
|
||||
- username: 1
|
||||
password: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68
|
||||
certificate: ./server.crt # 证书 PEM 格式,或者 证书的路径
|
||||
private-key: ./server.key # 证书对应的私钥 PEM 格式,或者私钥路径
|
||||
network: ["tcp", "udp"] # http2+http3
|
||||
congestion-controller: bbr
|
||||
# 下面两项为mTLS配置项,如果client-auth-type设置为 "verify-if-given" 或 "require-and-verify" 则client-auth-cert必须不为空
|
||||
# client-auth-type: "" # 可选值:""、"request"、"require-any"、"verify-if-given"、"require-and-verify"
|
||||
# client-auth-cert: string # 证书 PEM 格式,或者 证书的路径
|
||||
# 如果填写则开启ech(可由 mihomo generate ech-keypair <明文域名> 生成)
|
||||
# ech-key: |
|
||||
# -----BEGIN ECH KEYS-----
|
||||
# ACATwY30o/RKgD6hgeQxwrSiApLaCgU+HKh7B6SUrAHaDwBD/g0APwAAIAAgHjzK
|
||||
# madSJjYQIf9o1N5GXjkW4DEEeb17qMxHdwMdNnwADAABAAEAAQACAAEAAwAIdGVz
|
||||
# dC5jb20AAA==
|
||||
# -----END ECH KEYS-----
|
||||
|
||||
# 注意,listeners中的tun仅提供给高级用户使用,普通用户应使用顶层配置中的tun
|
||||
- name: tun-in-1
|
||||
type: tun
|
||||
|
||||
@@ -41,7 +41,7 @@ if [ "$1" = "fake-ip" ] && [ "$enable_redirect_dns" != "2" ]; then
|
||||
awk -v mode="$fake_ip_filter_mode" '
|
||||
!/^$/ && !/^#/ {
|
||||
# 跳过IPv4和IPv6地址
|
||||
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ || $0 ~ /:/) {
|
||||
if ($0 ~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\/[0-9]+)?$/ || $0 ~ /:/) {
|
||||
next
|
||||
}
|
||||
if (mode == "blacklist") {
|
||||
@@ -185,7 +185,7 @@ set_disable_qtype()
|
||||
yml_dns_get()
|
||||
{
|
||||
local section="$1" regex='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
|
||||
local enabled port type ip group dns_type dns_address interface specific_group node_resolve http3 ecs_subnet ecs_override disable_qtype_param
|
||||
local enabled port type ip group dns_type dns_address interface specific_group node_resolve direct_nameserver http3 skip_cert_verify ecs_subnet ecs_override disable_qtype_param disable_qtype disable_ipv4 disable_ipv6 disable_reuse
|
||||
|
||||
config_get_bool "enabled" "$section" "enabled" "1"
|
||||
[ "$enabled" = "0" ] && return
|
||||
@@ -378,6 +378,8 @@ begin
|
||||
smart_collect = '${44}' == '1'
|
||||
smart_collect_size = '${45}'
|
||||
fake_ip_range6 = '${46}'
|
||||
fake_ip_range6_enable = '${47}' == '1'
|
||||
global_ua = '${48}'
|
||||
default_dashboard = '$default_dashboard'
|
||||
yacd_type = '$yacd_type'
|
||||
dashboard_type = '$dashboard_type'
|
||||
@@ -408,6 +410,7 @@ begin
|
||||
Value['external-controller'] = '0.0.0.0:' + controller_port
|
||||
Value['secret'] = secret
|
||||
Value['bind-address'] = '*'
|
||||
Value['global-ua'] = global_ua if global_ua != '0'
|
||||
Value['external-ui'] = '/usr/share/openclash/ui'
|
||||
Value['external-ui-name'] = default_dashboard
|
||||
case default_dashboard
|
||||
@@ -480,7 +483,7 @@ begin
|
||||
else
|
||||
Value['dns']['enhanced-mode'] = 'fake-ip'
|
||||
Value['dns']['fake-ip-range'] = fake_ip_range
|
||||
if Value['dns']['ipv6']
|
||||
if Value['dns']['ipv6'] and fake_ip_range6_enable
|
||||
Value['dns']['fake-ip-range6'] = fake_ip_range6
|
||||
end
|
||||
end
|
||||
@@ -657,14 +660,13 @@ begin
|
||||
end
|
||||
if fake_ip_mode == 'fake-ip' && (china_ip_route || china_ip6_route)
|
||||
filter_mode = Value.dig('dns', 'fake-ip-filter-mode')
|
||||
filters = Value.dig('dns', 'fake-ip-filter') || []
|
||||
deleted_filters = filters.select { |f| f =~ /(geosite:?|rule-set:?).*(@cn|:cn|,cn|:china)/i }
|
||||
if filter_mode == 'blacklist' || filter_mode.nil?
|
||||
if !deleted_filters.any?
|
||||
(Value['dns']['fake-ip-filter'] ||= []) << 'geosite:cn'
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【geosite:cn】...')
|
||||
end
|
||||
else
|
||||
filter_rule = 'rule-set:oc-cn-domain'
|
||||
(Value['dns']['fake-ip-filter'] ||= []) << filter_rule
|
||||
end
|
||||
if filter_mode == 'whitelist'
|
||||
filters = Value.dig('dns', 'fake-ip-filter') || []
|
||||
deleted_filters = filters.select { |f| f =~ /(geosite:?|rule-set:?).*(@cn|:cn|,cn|:china)/i }
|
||||
if deleted_filters.any?
|
||||
Value['dns']['fake-ip-filter'] -= deleted_filters
|
||||
deleted_filters.each do |f|
|
||||
@@ -673,8 +675,14 @@ begin
|
||||
end
|
||||
end
|
||||
if filter_mode == 'rule'
|
||||
(Value['dns']['fake-ip-filter'] ||= []).unshift('GEOSITE,cn,real-ip')
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【GEOSITE,cn,real-ip】...')
|
||||
filter_rule = 'RULE-SET,oc-cn-domain,real-ip'
|
||||
(Value['dns']['fake-ip-filter'] ||= []).unshift(filter_rule)
|
||||
end
|
||||
Value['dns']['fake-ip-filter'].uniq!
|
||||
if filter_mode != 'whitelist'
|
||||
rule_set_hash = {'rule-providers+'=>{'oc-cn-domain'=>{'type'=>'http', 'interval'=>43200, 'behavior'=>'domain', 'format'=>'mrs', 'url'=>'https://raw.githubusercontent.com/MetaCubeX/meta-rules-dat/meta/geo/geosite/cn.mrs', 'path'=> './rule_provider/oc-cn-domain.mrs'}}}
|
||||
Value = YAML.overwrite(Value, rule_set_hash)
|
||||
YAML.LOG_TIP('Because Need Ensure Bypassing IP Option Work, Added The Fake-IP-Filter Rule【%s】...' % [filter_rule])
|
||||
end
|
||||
end
|
||||
rescue Exception => e
|
||||
|
||||
@@ -592,7 +592,7 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
};
|
||||
end;
|
||||
|
||||
#Mieru
|
||||
#Mieru
|
||||
if x['type'] == 'mieru' then
|
||||
threads << Thread.new{
|
||||
#port-range
|
||||
@@ -1138,6 +1138,19 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
uci_commands << uci_set + 'reality_short_id=\"' + x['reality-opts']['short-id'].to_s + '\"'
|
||||
end
|
||||
end
|
||||
if x.key?('encryption') then
|
||||
uci_commands << uci_set + 'vless_encryption=\"' + x['encryption'].to_s + '\"'
|
||||
end
|
||||
elsif x['network'].to_s == 'xhttp'
|
||||
uci_commands << uci_set + 'obfs_vless=xhttp'
|
||||
if x.key?('xhttp-opts') then
|
||||
if x['xhttp-opts'].key?('path') then
|
||||
uci_commands << uci_set + 'xhttp_opts_path=\"' + x['xhttp-opts']['path'].to_s + '\"'
|
||||
end
|
||||
if x['xhttp-opts'].key?('host') then
|
||||
uci_commands << uci_set + 'xhttp_opts_host=\"' + x['xhttp-opts']['host'].to_s + '\"'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
};
|
||||
@@ -1424,6 +1437,132 @@ ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e "
|
||||
};
|
||||
end;
|
||||
|
||||
if x['type'] == 'masque' then
|
||||
threads << Thread.new{
|
||||
#private-key
|
||||
if x.key?('private-key') then
|
||||
uci_commands << uci_set + 'masque_private_key=\"' + x['private-key'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#public-key
|
||||
if x.key?('public-key') then
|
||||
uci_commands << uci_set + 'masque_public_key=\"' + x['public-key'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#ip
|
||||
if x.key?('ip') then
|
||||
uci_commands << uci_set + 'masque_ip=\"' + x['ip'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#ipv6
|
||||
if x.key?('ipv6') then
|
||||
uci_commands << uci_set + 'masque_ipv6=\"' + x['ipv6'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#mtu
|
||||
if x.key?('mtu') then
|
||||
uci_commands << uci_set + 'masque_mtu=\"' + x['mtu'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#remote-dns-resolve
|
||||
if x.key?('remote-dns-resolve') then
|
||||
uci_commands << uci_set + 'masque_remote_dns_resolve=\"' + x['remote-dns-resolve'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#dns
|
||||
if x.key?('dns') then
|
||||
dns = uci_del + 'dns >/dev/null 2>&1'
|
||||
system(dns)
|
||||
x['dns'].each{
|
||||
|x|
|
||||
uci_commands << uci_add + 'masque_dns=\"' + x.to_s + '\"'
|
||||
}
|
||||
end
|
||||
};
|
||||
end;
|
||||
|
||||
if x['type'] == 'trusttunnel' then
|
||||
threads << Thread.new{
|
||||
#username
|
||||
if x.key?('username') then
|
||||
uci_commands << uci_set + 'trusttunnel_username=\"' + x['username'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#password
|
||||
if x.key?('password') then
|
||||
uci_commands << uci_set + 'trusttunnel_password=\"' + x['password'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#health-check
|
||||
if x.key?('health-check') then
|
||||
uci_commands << uci_set + 'trusttunnel_health_check=\"' + x['health-check'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#quic
|
||||
if x.key?('quic') then
|
||||
uci_commands << uci_set + 'trusttunnel_quic=\"' + x['quic'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
threads << Thread.new{
|
||||
#congestion-controller
|
||||
if x.key?('congestion-controller') then
|
||||
uci_commands << uci_set + 'trusttunnel_congestion_controller=\"' + x['congestion-controller'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#alpn
|
||||
threads << Thread.new{
|
||||
if x.key?('alpn') then
|
||||
alpn = uci_del + 'alpn >/dev/null 2>&1'
|
||||
system(alpn)
|
||||
x['alpn'].each{
|
||||
|x|
|
||||
uci_commands << uci_add + 'alpn=\"' + x.to_s + '\"'
|
||||
}
|
||||
end
|
||||
};
|
||||
|
||||
#sni
|
||||
threads << Thread.new{
|
||||
if x.key?('sni') then
|
||||
uci_commands << uci_set + 'sni=\"' + x['sni'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#skip-cert-verify
|
||||
threads << Thread.new{
|
||||
if x.key?('skip-cert-verify') then
|
||||
uci_commands << uci_set + 'skip_cert_verify=\"' + x['skip-cert-verify'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
|
||||
#client_fingerprint
|
||||
threads << Thread.new{
|
||||
if x.key?('client-fingerprint') then
|
||||
uci_commands << uci_set + 'client_fingerprint=\"' + x['client-fingerprint'].to_s + '\"'
|
||||
end
|
||||
};
|
||||
end;
|
||||
|
||||
#加入策略组
|
||||
threads << Thread.new{
|
||||
#加入策略组
|
||||
|
||||
@@ -186,135 +186,6 @@ yml_servers_set()
|
||||
config_get "name" "$section" "name" ""
|
||||
config_get "server" "$section" "server" ""
|
||||
config_get "port" "$section" "port" ""
|
||||
config_get "dialer_proxy" "$section" "dialer_proxy" ""
|
||||
config_get "cipher" "$section" "cipher" ""
|
||||
config_get "cipher_ssr" "$section" "cipher_ssr" ""
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "securitys" "$section" "securitys" ""
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "obfs" "$section" "obfs" ""
|
||||
config_get "obfs_ssr" "$section" "obfs_ssr" ""
|
||||
config_get "obfs_param" "$section" "obfs_param" ""
|
||||
config_get "obfs_vmess" "$section" "obfs_vmess" ""
|
||||
config_get "obfs_trojan" "$section" "obfs_trojan" ""
|
||||
config_get "protocol" "$section" "protocol" ""
|
||||
config_get "protocol_param" "$section" "protocol_param" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
config_get "mux" "$section" "mux" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "tls" "$section" "tls" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "alterId" "$section" "alterId" ""
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "psk" "$section" "psk" ""
|
||||
config_get "obfs_snell" "$section" "obfs_snell" ""
|
||||
config_get "snell_version" "$section" "snell_version" ""
|
||||
config_get "sni" "$section" "sni" ""
|
||||
config_get "alpn" "$section" "alpn" ""
|
||||
config_get "http_path" "$section" "http_path" ""
|
||||
config_get "keep_alive" "$section" "keep_alive" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "h2_path" "$section" "h2_path" ""
|
||||
config_get "h2_host" "$section" "h2_host" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "max_early_data" "$section" "max_early_data" ""
|
||||
config_get "early_data_header_name" "$section" "early_data_header_name" ""
|
||||
config_get "trojan_ws_path" "$section" "trojan_ws_path" ""
|
||||
config_get "trojan_ws_headers" "$section" "trojan_ws_headers" ""
|
||||
config_get "interface_name" "$section" "interface_name" ""
|
||||
config_get "routing_mark" "$section" "routing_mark" ""
|
||||
config_get "obfs_vless" "$section" "obfs_vless" ""
|
||||
config_get "vless_flow" "$section" "vless_flow" ""
|
||||
config_get "http_headers" "$section" "http_headers" ""
|
||||
config_get "hysteria_protocol" "$section" "hysteria_protocol" ""
|
||||
config_get "hysteria2_protocol" "$section" "hysteria2_protocol" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_auth" "$section" "hysteria_auth" ""
|
||||
config_get "hysteria_auth_str" "$section" "hysteria_auth_str" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "recv_window_conn" "$section" "recv_window_conn" ""
|
||||
config_get "recv_window" "$section" "recv_window" ""
|
||||
config_get "disable_mtu_discovery" "$section" "disable_mtu_discovery" ""
|
||||
config_get "initial_stream_receive_window" "$section" "initial_stream_receive_window" ""
|
||||
config_get "max_stream_receive_window" "$section" "max_stream_receive_window" ""
|
||||
config_get "initial_connection_receive_window" "$section" "initial_connection_receive_window" ""
|
||||
config_get "max_connection_receive_window" "$section" "max_connection_receive_window" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "global_padding" "$section" "global_padding" ""
|
||||
config_get "authenticated_length" "$section" "authenticated_length" ""
|
||||
config_get "wg_ip" "$section" "wg_ip" ""
|
||||
config_get "wg_ipv6" "$section" "wg_ipv6" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_dns" "$section" "wg_dns" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_mtu" "$section" "wg_mtu" ""
|
||||
config_get "tc_ip" "$section" "tc_ip" ""
|
||||
config_get "tc_token" "$section" "tc_token" ""
|
||||
config_get "tc_uuid" "$section" "tc_uuid" ""
|
||||
config_get "tc_password" "$section" "tc_password" ""
|
||||
config_get "udp_relay_mode" "$section" "udp_relay_mode" ""
|
||||
config_get "congestion_controller" "$section" "congestion_controller" ""
|
||||
config_get "tc_alpn" "$section" "tc_alpn" ""
|
||||
config_get "disable_sni" "$section" "disable_sni" ""
|
||||
config_get "reduce_rtt" "$section" "reduce_rtt" ""
|
||||
config_get "heartbeat_interval" "$section" "heartbeat_interval" ""
|
||||
config_get "request_timeout" "$section" "request_timeout" ""
|
||||
config_get "max_udp_relay_packet_size" "$section" "max_udp_relay_packet_size" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "fingerprint" "$section" "fingerprint" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
config_get "max_open_streams" "$section" "max_open_streams" ""
|
||||
config_get "obfs_password" "$section" "obfs_password" ""
|
||||
config_get "packet_addr" "$section" "packet_addr" ""
|
||||
config_get "client_fingerprint" "$section" "client_fingerprint" ""
|
||||
config_get "ip_version" "$section" "ip_version" ""
|
||||
config_get "tfo" "$section" "tfo" ""
|
||||
config_get "udp_over_tcp" "$section" "udp_over_tcp" ""
|
||||
config_get "reality_public_key" "$section" "reality_public_key" ""
|
||||
config_get "reality_short_id" "$section" "reality_short_id" ""
|
||||
config_get "obfs_version_hint" "$section" "obfs_version_hint" ""
|
||||
config_get "obfs_restls_script" "$section" "obfs_restls_script" ""
|
||||
config_get "multiplex" "$section" "multiplex" ""
|
||||
config_get "multiplex_protocol" "$section" "multiplex_protocol" ""
|
||||
config_get "multiplex_max_connections" "$section" "multiplex_max_connections" ""
|
||||
config_get "multiplex_min_streams" "$section" "multiplex_min_streams" ""
|
||||
config_get "multiplex_max_streams" "$section" "multiplex_max_streams" ""
|
||||
config_get "multiplex_padding" "$section" "multiplex_padding" ""
|
||||
config_get "multiplex_statistic" "$section" "multiplex_statistic" ""
|
||||
config_get "multiplex_only_tcp" "$section" "multiplex_only_tcp" ""
|
||||
config_get "other_parameters" "$section" "other_parameters" ""
|
||||
config_get "hysteria_obfs_password" "$section" "hysteria_obfs_password" ""
|
||||
config_get "port_range" "$section" "port_range" ""
|
||||
config_get "username" "$section" "username" ""
|
||||
config_get "transport" "$section" "transport" "TCP"
|
||||
config_get "multiplexing" "$section" "multiplexing" "MULTIPLEXING_LOW"
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "private_key_passphrase" "$section" "private_key_passphrase" ""
|
||||
config_get "host_key" "$section" "host_key" ""
|
||||
config_get "host_key_algorithms" "$section" "host_key_algorithms" ""
|
||||
config_get "idle_session_check_interval" "$section" "idle_session_check_interval" ""
|
||||
config_get "idle_session_timeout" "$section" "idle_session_timeout" ""
|
||||
config_get "min_idle_session" "$section" "min_idle_session" ""
|
||||
config_get "sudoku_key" "$section" "sudoku_key" ""
|
||||
config_get "aead_method" "$section" "aead_method" "none"
|
||||
config_get "padding_min" "$section" "padding_min" ""
|
||||
config_get "padding_max" "$section" "padding_max" ""
|
||||
config_get "table_type" "$section" "table_type" "prefer_ascii"
|
||||
config_get "http_mask" "$section" "http_mask" "true"
|
||||
|
||||
if [ "$enabled" = "0" ]; then
|
||||
return
|
||||
@@ -336,11 +207,12 @@ yml_servers_set()
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -z "$password" ]; then
|
||||
if [ "$type" = "ss" ] || [ "$type" = "trojan" ] || [ "$type" = "ssr" ]; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
if [ "$type" = "ss" ] || [ "$type" = "trojan" ] || [ "$type" = "ssr" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
if [ -z "$password" ]; then
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$config" ] && [ "$config" != "$CONFIG_NAME" ] && [ "$config" != "all" ]; then
|
||||
return
|
||||
@@ -364,59 +236,27 @@ yml_servers_set()
|
||||
fi
|
||||
LOG_OUT "Start Writing【$CONFIG_NAME - $type - $name】Proxy To Config File..."
|
||||
|
||||
if [ "$obfs" != "none" ] && [ -n "$obfs" ]; then
|
||||
if [ "$obfs" = "websocket" ]; then
|
||||
obfss="plugin: v2ray-plugin"
|
||||
elif [ "$obfs" = "shadow-tls" ]; then
|
||||
obfss="plugin: shadow-tls"
|
||||
elif [ "$obfs" = "restls" ]; then
|
||||
obfss="plugin: restls"
|
||||
else
|
||||
obfss="plugin: obfs"
|
||||
fi
|
||||
else
|
||||
obfss=""
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "ws" ]; then
|
||||
obfs_vless="network: ws"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "grpc" ]; then
|
||||
obfs_vless="network: grpc"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vless" = "tcp" ]; then
|
||||
obfs_vless="network: tcp"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "websocket" ]; then
|
||||
obfs_vmess="network: ws"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "http" ]; then
|
||||
obfs_vmess="network: http"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "h2" ]; then
|
||||
obfs_vmess="network: h2"
|
||||
fi
|
||||
|
||||
if [ "$obfs_vmess" = "grpc" ]; then
|
||||
obfs_vmess="network: grpc"
|
||||
fi
|
||||
|
||||
if [ ! -z "$custom" ] && [ "$type" = "vmess" ]; then
|
||||
custom="Host: \"$custom\""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ]; then
|
||||
if [ "$type" != "vmess" ]; then
|
||||
path="path: \"$path\""
|
||||
elif [ "$obfs_vmess" = "network: ws" ]; then
|
||||
path="ws-path: \"$path\""
|
||||
fi
|
||||
fi
|
||||
config_get "dialer_proxy" "$section" "dialer_proxy" ""
|
||||
config_get "udp" "$section" "udp" ""
|
||||
config_get "skip_cert_verify" "$section" "skip_cert_verify" ""
|
||||
config_get "tls" "$section" "tls" ""
|
||||
config_get "sni" "$section" "sni" ""
|
||||
config_get "alpn" "$section" "alpn" ""
|
||||
config_get "fingerprint" "$section" "fingerprint" ""
|
||||
config_get "client_fingerprint" "$section" "client_fingerprint" ""
|
||||
config_get "ip_version" "$section" "ip_version" ""
|
||||
config_get "tfo" "$section" "tfo" ""
|
||||
config_get "multiplex" "$section" "multiplex" ""
|
||||
config_get "multiplex_protocol" "$section" "multiplex_protocol" ""
|
||||
config_get "multiplex_max_connections" "$section" "multiplex_max_connections" ""
|
||||
config_get "multiplex_min_streams" "$section" "multiplex_min_streams" ""
|
||||
config_get "multiplex_max_streams" "$section" "multiplex_max_streams" ""
|
||||
config_get "multiplex_padding" "$section" "multiplex_padding" ""
|
||||
config_get "multiplex_statistic" "$section" "multiplex_statistic" ""
|
||||
config_get "multiplex_only_tcp" "$section" "multiplex_only_tcp" ""
|
||||
config_get "interface_name" "$section" "interface_name" ""
|
||||
config_get "routing_mark" "$section" "routing_mark" ""
|
||||
config_get "other_parameters" "$section" "other_parameters" ""
|
||||
|
||||
if [ "$client_fingerprint" = "none" ]; then
|
||||
client_fingerprint=""
|
||||
@@ -428,6 +268,35 @@ yml_servers_set()
|
||||
|
||||
#ss
|
||||
if [ "$type" = "ss" ]; then
|
||||
config_get "cipher" "$section" "cipher" ""
|
||||
config_get "obfs" "$section" "obfs" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
config_get "mux" "$section" "mux" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "obfs_password" "$section" "obfs_password" ""
|
||||
config_get "obfs_version_hint" "$section" "obfs_version_hint" ""
|
||||
config_get "obfs_restls_script" "$section" "obfs_restls_script" ""
|
||||
config_get "udp_over_tcp" "$section" "udp_over_tcp" ""
|
||||
|
||||
if [ "$obfs" != "none" ] && [ -n "$obfs" ]; then
|
||||
if [ "$obfs" = "websocket" ]; then
|
||||
obfss="plugin: v2ray-plugin"
|
||||
elif [ "$obfs" = "shadow-tls" ]; then
|
||||
obfss="plugin: shadow-tls"
|
||||
elif [ "$obfs" = "restls" ]; then
|
||||
obfss="plugin: restls"
|
||||
else
|
||||
obfss="plugin: obfs"
|
||||
fi
|
||||
else
|
||||
obfss=""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ]; then
|
||||
path="path: \"$path\""
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -528,6 +397,12 @@ fi
|
||||
|
||||
#ssr
|
||||
if [ "$type" = "ssr" ]; then
|
||||
config_get "cipher_ssr" "$section" "cipher_ssr" ""
|
||||
config_get "obfs_ssr" "$section" "obfs_ssr" ""
|
||||
config_get "protocol" "$section" "protocol" ""
|
||||
config_get "obfs_param" "$section" "obfs_param" ""
|
||||
config_get "protocol_param" "$section" "protocol_param" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -557,6 +432,48 @@ fi
|
||||
|
||||
#vmess
|
||||
if [ "$type" = "vmess" ]; then
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "alterId" "$section" "alterId" ""
|
||||
config_get "securitys" "$section" "securitys" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "global_padding" "$section" "global_padding" ""
|
||||
config_get "authenticated_length" "$section" "authenticated_length" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "obfs_vmess" "$section" "obfs_vmess" ""
|
||||
config_get "custom" "$section" "custom" ""
|
||||
config_get "path" "$section" "path" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "max_early_data" "$section" "max_early_data" ""
|
||||
config_get "early_data_header_name" "$section" "early_data_header_name" ""
|
||||
config_get "http_path" "$section" "http_path" ""
|
||||
config_get "keep_alive" "$section" "keep_alive" ""
|
||||
config_get "h2_path" "$section" "h2_path" ""
|
||||
config_get "h2_host" "$section" "h2_host" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
|
||||
if [ "$obfs_vmess" = "websocket" ]; then
|
||||
obfs_vmess="network: ws"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "http" ]; then
|
||||
obfs_vmess="network: http"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "h2" ]; then
|
||||
obfs_vmess="network: h2"
|
||||
fi
|
||||
if [ "$obfs_vmess" = "grpc" ]; then
|
||||
obfs_vmess="network: grpc"
|
||||
fi
|
||||
|
||||
if [ ! -z "$custom" ]; then
|
||||
custom="Host: \"$custom\""
|
||||
fi
|
||||
|
||||
if [ ! -z "$path" ] && [ "$obfs_vmess" = "network: ws" ]; then
|
||||
path="ws-path: \"$path\""
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -702,6 +619,11 @@ fi
|
||||
|
||||
#anytls
|
||||
if [ "$type" = "anytls" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "idle_session_check_interval" "$section" "idle_session_check_interval" ""
|
||||
config_get "idle_session_timeout" "$section" "idle_session_timeout" ""
|
||||
config_get "min_idle_session" "$section" "min_idle_session" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -758,6 +680,11 @@ fi
|
||||
|
||||
#Mieru
|
||||
if [ "$type" = "mieru" ]; then
|
||||
config_get "port_range" "$section" "port_range" ""
|
||||
config_get "username" "$section" "username" ""
|
||||
config_get "transport" "$section" "transport" "TCP"
|
||||
config_get "multiplexing" "$section" "multiplexing" "MULTIPLEXING_LOW"
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -788,6 +715,21 @@ fi
|
||||
|
||||
#Tuic
|
||||
if [ "$type" = "tuic" ]; then
|
||||
config_get "tc_ip" "$section" "tc_ip" ""
|
||||
config_get "tc_token" "$section" "tc_token" ""
|
||||
config_get "tc_uuid" "$section" "tc_uuid" ""
|
||||
config_get "tc_password" "$section" "tc_password" ""
|
||||
config_get "udp_relay_mode" "$section" "udp_relay_mode" ""
|
||||
config_get "congestion_controller" "$section" "congestion_controller" ""
|
||||
config_get "tc_alpn" "$section" "tc_alpn" ""
|
||||
config_get "disable_sni" "$section" "disable_sni" ""
|
||||
config_get "reduce_rtt" "$section" "reduce_rtt" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "heartbeat_interval" "$section" "heartbeat_interval" ""
|
||||
config_get "request_timeout" "$section" "request_timeout" ""
|
||||
config_get "max_udp_relay_packet_size" "$section" "max_udp_relay_packet_size" ""
|
||||
config_get "max_open_streams" "$section" "max_open_streams" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -874,6 +816,14 @@ fi
|
||||
|
||||
#WireGuard
|
||||
if [ "$type" = "wireguard" ]; then
|
||||
config_get "wg_ip" "$section" "wg_ip" ""
|
||||
config_get "wg_ipv6" "$section" "wg_ipv6" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "public_key" "$section" "public_key" ""
|
||||
config_get "preshared_key" "$section" "preshared_key" ""
|
||||
config_get "wg_dns" "$section" "wg_dns" ""
|
||||
config_get "wg_mtu" "$section" "wg_mtu" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -905,7 +855,7 @@ cat >> "$SERVER_FILE" <<-EOF
|
||||
preshared-key: "$preshared_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$preshared_key" ]; then
|
||||
if [ -n "$wg_dns" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
dns:
|
||||
EOF
|
||||
@@ -925,6 +875,22 @@ fi
|
||||
|
||||
#hysteria
|
||||
if [ "$type" = "hysteria" ]; then
|
||||
config_get "hysteria_protocol" "$section" "hysteria_protocol" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_auth" "$section" "hysteria_auth" ""
|
||||
config_get "hysteria_auth_str" "$section" "hysteria_auth_str" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "recv_window_conn" "$section" "recv_window_conn" ""
|
||||
config_get "recv_window" "$section" "recv_window" ""
|
||||
config_get "disable_mtu_discovery" "$section" "disable_mtu_discovery" ""
|
||||
config_get "fast_open" "$section" "fast_open" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1029,6 +995,22 @@ fi
|
||||
|
||||
#hysteria2
|
||||
if [ "$type" = "hysteria2" ]; then
|
||||
config_get "password" "$section" "password" ""
|
||||
config_get "hysteria_up" "$section" "hysteria_up" ""
|
||||
config_get "hysteria_down" "$section" "hysteria_down" ""
|
||||
config_get "hysteria_alpn" "$section" "hysteria_alpn" ""
|
||||
config_get "hysteria_obfs" "$section" "hysteria_obfs" ""
|
||||
config_get "hysteria_obfs_password" "$section" "hysteria_obfs_password" ""
|
||||
config_get "hysteria_ca" "$section" "hysteria_ca" ""
|
||||
config_get "hysteria_ca_str" "$section" "hysteria_ca_str" ""
|
||||
config_get "initial_stream_receive_window" "$section" "initial_stream_receive_window" ""
|
||||
config_get "max_stream_receive_window" "$section" "max_stream_receive_window" ""
|
||||
config_get "initial_connection_receive_window" "$section" "initial_connection_receive_window" ""
|
||||
config_get "max_connection_receive_window" "$section" "max_connection_receive_window" ""
|
||||
config_get "ports" "$section" "ports" ""
|
||||
config_get "hysteria2_protocol" "$section" "hysteria2_protocol" ""
|
||||
config_get "hop_interval" "$section" "hop_interval" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1096,7 +1078,7 @@ EOF
|
||||
fi
|
||||
if [ -n "$max_stream_receive_window" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
max_stream_receive_window: "$max_stream_receive_window"
|
||||
max-stream-receive-window: "$max_stream_receive_window"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$initial_connection_receive_window" ]; then
|
||||
@@ -1133,6 +1115,35 @@ fi
|
||||
|
||||
#vless
|
||||
if [ "$type" = "vless" ]; then
|
||||
config_get "uuid" "$section" "uuid" ""
|
||||
config_get "xudp" "$section" "xudp" ""
|
||||
config_get "packet_addr" "$section" "packet_addr" ""
|
||||
config_get "packet_encoding" "$section" "packet_encoding" ""
|
||||
config_get "servername" "$section" "servername" ""
|
||||
config_get "obfs_vless" "$section" "obfs_vless" ""
|
||||
config_get "ws_opts_path" "$section" "ws_opts_path" ""
|
||||
config_get "ws_opts_headers" "$section" "ws_opts_headers" ""
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "reality_public_key" "$section" "reality_public_key" ""
|
||||
config_get "reality_short_id" "$section" "reality_short_id" ""
|
||||
config_get "vless_flow" "$section" "vless_flow" ""
|
||||
config_get "xhttp_opts_path" "$section" "xhttp_opts_path" ""
|
||||
config_get "xhttp_opts_host" "$section" "xhttp_opts_host" ""
|
||||
config_get "vless_encryption" "$section" "vless_encryption" ""
|
||||
|
||||
if [ "$obfs_vless" = "ws" ]; then
|
||||
obfs_vless="network: ws"
|
||||
fi
|
||||
if [ "$obfs_vless" = "grpc" ]; then
|
||||
obfs_vless="network: grpc"
|
||||
fi
|
||||
if [ "$obfs_vless" = "tcp" ]; then
|
||||
obfs_vless="network: tcp"
|
||||
fi
|
||||
if [ "$obfs_vless" = "xhttp" ]; then
|
||||
obfs_vless="network: xhttp"
|
||||
fi
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1232,6 +1243,11 @@ EOF
|
||||
if [ ! -z "$vless_flow" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
flow: "$vless_flow"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$vless_encryption" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
encryption: "$vless_encryption"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$reality_public_key" ] || [ -n "$reality_short_id" ]; then
|
||||
@@ -1247,6 +1263,21 @@ EOF
|
||||
if [ -n "$reality_short_id" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
short-id: "$reality_short_id"
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
if [ "$obfs_vless" = "network: xhttp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
xhttp-opts:
|
||||
EOF
|
||||
if [ -n "$xhttp_opts_path" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
path: "$xhttp_opts_path"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$xhttp_opts_host" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
host: "$xhttp_opts_host"
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
@@ -1276,6 +1307,13 @@ fi
|
||||
|
||||
#ssh
|
||||
if [ "$type" = "ssh" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "private_key" "$section" "private_key" ""
|
||||
config_get "private_key_passphrase" "$section" "private_key_passphrase" ""
|
||||
config_get "host_key" "$section" "host_key" ""
|
||||
config_get "host_key_algorithms" "$section" "host_key_algorithms" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1318,6 +1356,9 @@ fi
|
||||
|
||||
#socks5
|
||||
if [ "$type" = "socks5" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1358,6 +1399,10 @@ fi
|
||||
|
||||
#http
|
||||
if [ "$type" = "http" ]; then
|
||||
config_get "auth_name" "$section" "auth_name" ""
|
||||
config_get "auth_pass" "$section" "auth_pass" ""
|
||||
config_get "http_headers" "$section" "http_headers" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1399,6 +1444,11 @@ fi
|
||||
|
||||
#trojan
|
||||
if [ "$type" = "trojan" ]; then
|
||||
config_get "grpc_service_name" "$section" "grpc_service_name" ""
|
||||
config_get "obfs_trojan" "$section" "obfs_trojan" ""
|
||||
config_get "trojan_ws_path" "$section" "trojan_ws_path" ""
|
||||
config_get "trojan_ws_headers" "$section" "trojan_ws_headers" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1467,6 +1517,11 @@ fi
|
||||
|
||||
#snell
|
||||
if [ "$type" = "snell" ]; then
|
||||
config_get "psk" "$section" "psk" ""
|
||||
config_get "snell_version" "$section" "snell_version" ""
|
||||
config_get "obfs_snell" "$section" "obfs_snell" ""
|
||||
config_get "host" "$section" "host" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1490,6 +1545,13 @@ fi
|
||||
|
||||
#Sudoku
|
||||
if [ "$type" = "sudoku" ]; then
|
||||
config_get "sudoku_key" "$section" "sudoku_key" ""
|
||||
config_get "aead_method" "$section" "aead_method" "none"
|
||||
config_get "padding_min" "$section" "padding_min" ""
|
||||
config_get "padding_max" "$section" "padding_max" ""
|
||||
config_get "table_type" "$section" "table_type" "prefer_ascii"
|
||||
config_get "http_mask" "$section" "http_mask" "true"
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
@@ -1528,6 +1590,132 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
#MASQUE
|
||||
if [ "$type" = "masque" ]; then
|
||||
config_get "masque_private_key" "$section" "masque_private_key" ""
|
||||
config_get "masque_public_key" "$section" "masque_public_key" ""
|
||||
config_get "masque_ip" "$section" "masque_ip" ""
|
||||
config_get "masque_ipv6" "$section" "masque_ipv6" ""
|
||||
config_get "masque_mtu" "$section" "masque_mtu" ""
|
||||
config_get "masque_remote_dns_resolve" "$section" "masque_remote_dns_resolve" ""
|
||||
config_get "masque_dns" "$section" "masque_dns" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
server: "$server"
|
||||
port: $port
|
||||
EOF
|
||||
if [ -n "$masque_private_key" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
private-key: "$masque_private_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_public_key" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
public-key: "$masque_public_key"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_ip" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
ip: "$masque_ip"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_ipv6" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
ipv6: "$masque_ipv6"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_mtu" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
mtu: $masque_mtu
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$masque_remote_dns_resolve" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
remote-dns-resolve: $masque_remote_dns_resolve
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$udp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
udp: $udp
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$masque_dns" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
dns:
|
||||
EOF
|
||||
config_list_foreach "$section" "masque_dns" set_alpn
|
||||
fi
|
||||
fi
|
||||
|
||||
#TrustTunnel
|
||||
if [ "$type" = "trusttunnel" ]; then
|
||||
config_get "trusttunnel_username" "$section" "trusttunnel_username" ""
|
||||
config_get "trusttunnel_password" "$section" "trusttunnel_password" ""
|
||||
config_get "trusttunnel_health_check" "$section" "trusttunnel_health_check" ""
|
||||
config_get "trusttunnel_quic" "$section" "trusttunnel_quic" ""
|
||||
config_get "trusttunnel_congestion_controller" "$section" "trusttunnel_congestion_controller" ""
|
||||
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
- name: "$name"
|
||||
type: $type
|
||||
server: "$server"
|
||||
port: $port
|
||||
EOF
|
||||
if [ -n "$trusttunnel_username" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
username: "$trusttunnel_username"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_password" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
password: "$trusttunnel_password"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_health_check" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
health-check: $trusttunnel_health_check
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_quic" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
quic: $trusttunnel_quic
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$trusttunnel_congestion_controller" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
congestion-controller: "$trusttunnel_congestion_controller"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$client_fingerprint" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
client-fingerprint: "$client_fingerprint"
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$udp" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
udp: $udp
|
||||
EOF
|
||||
fi
|
||||
if [ -n "$sni" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
sni: "$sni"
|
||||
EOF
|
||||
fi
|
||||
if [ ! -z "$alpn" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
alpn:
|
||||
EOF
|
||||
config_list_foreach "$section" "alpn" set_alpn
|
||||
fi
|
||||
if [ ! -z "$skip_cert_verify" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
skip-cert-verify: $skip_cert_verify
|
||||
EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
#ip_version
|
||||
if [ ! -z "$ip_version" ]; then
|
||||
cat >> "$SERVER_FILE" <<-EOF
|
||||
|
||||
@@ -21,6 +21,9 @@ yml_other_set()
|
||||
|
||||
begin
|
||||
thread_pool = [];
|
||||
# GEOIP replace
|
||||
geoip_pattern = /GEOIP,([A-Za-z]{2}),([^,]+)(,.*)?/;
|
||||
match_pattern = /(^MATCH.*|^FINAL.*)/;
|
||||
thread_pool << Thread.new{
|
||||
#BT/P2P DIRECT Rules
|
||||
begin
|
||||
@@ -102,10 +105,6 @@ yml_other_set()
|
||||
end;
|
||||
end;
|
||||
|
||||
# GEOIP replace
|
||||
geoip_pattern = /GEOIP,([A-Za-z]{2}),([^,]+)(,.*)?/;
|
||||
match_pattern = /(^MATCH.*|^FINAL.*)/;
|
||||
|
||||
Value['rules'].to_a.collect!{|x|
|
||||
x.to_s.gsub(geoip_pattern, 'GEOIP,\1,DIRECT\3').gsub(match_pattern, 'MATCH,DIRECT')
|
||||
};
|
||||
@@ -136,6 +135,18 @@ yml_other_set()
|
||||
{ file: '/etc/openclash/custom/openclash_custom_rules_2.list', position: 'bottom' }
|
||||
];
|
||||
|
||||
# 在开始对 custom_files 进行插入之前,记录当前 rules 中 GEOIP、MATCH、DST-PORT,80 的原始规则文本(锚点)
|
||||
anchors_orig = {}
|
||||
if Value.has_key?('rules') and not Value['rules'].to_a.empty? then
|
||||
anchors_orig[:dst80_rule] = Value['rules'].grep(/DST-PORT,80/).last
|
||||
anchors_orig[:match_rule] = Value['rules'].grep(match_pattern).first
|
||||
anchors_orig[:geo_rule] = Value['rules'].grep(geoip_pattern).first
|
||||
else
|
||||
anchors_orig[:dst80_rule] = nil
|
||||
anchors_orig[:match_rule] = nil
|
||||
anchors_orig[:geo_rule] = nil
|
||||
end;
|
||||
|
||||
custom_files.each{|file_info|
|
||||
if File::exist?(file_info[:file]) then
|
||||
custom_data = YAML.load_file(file_info[:file]);
|
||||
@@ -150,6 +161,13 @@ yml_other_set()
|
||||
[]
|
||||
end;
|
||||
|
||||
rule_providers_array = case custom_data.class.to_s
|
||||
when 'Hash'
|
||||
custom_data['rule-providers'].to_a if custom_data['rule-providers'].class.to_s == 'Hash'
|
||||
else
|
||||
[]
|
||||
end;
|
||||
|
||||
next unless rules_array;
|
||||
|
||||
ipv4_regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
@@ -157,9 +175,10 @@ yml_other_set()
|
||||
cidr_regex = /\/\d+$/;
|
||||
rule_suffix_regex = /^no-resolve$|^src$/;
|
||||
|
||||
ip_rule_types = ['IP-CIDR', 'IP-CIDR6', 'SRC-IP-CIDR', 'SRC-IP-CIDR6', 'IP-SUFFIX', 'SRC-IP-SUFFIX'];
|
||||
transformed_rules = rules_array.map{|x|
|
||||
parts = x.split(',');
|
||||
if parts.length >= 2 then
|
||||
if parts.length >= 2 && ip_rule_types.include?(parts[0].strip.upcase) then
|
||||
ip_part = parts[1].strip;
|
||||
if ip_part !~ cidr_regex then
|
||||
# IPv4
|
||||
@@ -194,11 +213,15 @@ yml_other_set()
|
||||
if file_info[:position] == 'top' then
|
||||
valid_rules.reverse.each{|x| Value['rules'].insert(0,x)};
|
||||
else
|
||||
if Value['rules'].grep(/GEOIP/)[0].nil? or Value['rules'].grep(/GEOIP/)[0].empty? then
|
||||
ruby_add_index = Value['rules'].index(Value['rules'].grep(/DST-PORT,80/).last);
|
||||
ruby_add_index ||= Value['rules'].index(Value['rules'].grep(/(MATCH|FINAL)/).first);
|
||||
else
|
||||
ruby_add_index = Value['rules'].index(Value['rules'].grep(/GEOIP/).first);
|
||||
ruby_add_index = nil;
|
||||
if anchors_orig[:dst80_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:dst80_rule])
|
||||
end;
|
||||
if ruby_add_index.nil? and anchors_orig[:match_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:match_rule])
|
||||
end;
|
||||
if ruby_add_index.nil? and anchors_orig[:geo_rule]
|
||||
ruby_add_index = Value['rules'].rindex(anchors_orig[:geo_rule])
|
||||
end;
|
||||
ruby_add_index ||= -1;
|
||||
|
||||
@@ -209,6 +232,11 @@ yml_other_set()
|
||||
else
|
||||
Value['rules'] = valid_rules.uniq;
|
||||
end;
|
||||
|
||||
if rule_providers_array and not rule_providers_array.empty? then
|
||||
Value['rule-providers'] ||= {};
|
||||
Value['rule-providers'] = Value['rule-providers'].merge!(custom_data['rule-providers']);
|
||||
end;
|
||||
end;
|
||||
};
|
||||
|
||||
@@ -256,19 +284,13 @@ yml_other_set()
|
||||
thread_pool << Thread.new{
|
||||
threads = [];
|
||||
|
||||
#provider path
|
||||
#provider CDN
|
||||
begin
|
||||
provider_configs = {'proxy-providers' => 'proxy_provider', 'rule-providers' => 'rule_provider'};
|
||||
provider_configs.each do |provider_type, path_prefix|
|
||||
if Value.key?(provider_type) then
|
||||
if Value.key?(provider_type) && Value[provider_type].is_a?(Hash) then
|
||||
Value[provider_type].each{|name, config|
|
||||
threads << Thread.new {
|
||||
if config['path'] and not config['path'] =~ /.\/#{path_prefix}\/*/ then
|
||||
config['path'] = './'+path_prefix+'/'+File.basename(config['path']);
|
||||
elsif not config['path'] and config['type'] == 'http' then
|
||||
config['path'] = './'+path_prefix+'/'+name;
|
||||
end;
|
||||
|
||||
# CDN
|
||||
if '$github_address_mod' != '0' and config['url'] then
|
||||
if config['url'] =~ /^https:\/\/raw.githubusercontent.com/ then
|
||||
@@ -293,12 +315,12 @@ yml_other_set()
|
||||
end;
|
||||
end;
|
||||
rescue Exception => e
|
||||
YAML.LOG_ERROR('Edit Provider Path Failed,【' + e.message + '】');
|
||||
YAML.LOG_ERROR('Edit Provider CDN Failed,【' + e.message + '】');
|
||||
end;
|
||||
|
||||
# tolerance
|
||||
begin
|
||||
if '$tolerance' != '0' and Value.key?('proxy-groups') then
|
||||
if '$tolerance' != '0' and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if group['type'] == 'url-test' then
|
||||
@@ -314,7 +336,7 @@ yml_other_set()
|
||||
# URL-Test interval
|
||||
begin
|
||||
if '$urltest_interval_mod' != '0' then
|
||||
if Value.key?('proxy-groups') then
|
||||
if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then
|
||||
@@ -349,7 +371,7 @@ yml_other_set()
|
||||
};
|
||||
};
|
||||
end;
|
||||
if Value.key?('proxy-groups') then
|
||||
if Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if ['url-test', 'fallback', 'load-balance', 'smart'].include?(group['type']) then
|
||||
@@ -365,7 +387,7 @@ yml_other_set()
|
||||
|
||||
# smart auto switch
|
||||
begin
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') then
|
||||
if ('${8}' == '1' or '${9}' == '1' or '${11}' != '0' or '${12}' != '0' or '${12}' == '1' or '${13}' == '1') and Value.key?('proxy-groups') and Value['proxy-groups'].is_a?(Array) then
|
||||
Value['proxy-groups'].each{|group|
|
||||
threads << Thread.new {
|
||||
if '${8}' == '1' and ['url-test', 'load-balance'].include?(group['type']) then
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
/*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,(function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;n<t;n+=1)i+=e;return i},isNegativeZero:function(e){return 0===e&&Number.NEGATIVE_INFINITY===1/e},extend:function(e,t){var n,i,r,o;if(t)for(n=0,i=(o=Object.keys(t)).length;n<i;n+=1)e[r=o[n]]=t[r];return e}};function i(e,t){var n="",i=e.reason||"(unknown reason)";return e.mark?(e.mark.name&&(n+='in "'+e.mark.name+'" '),n+="("+(e.mark.line+1)+":"+(e.mark.column+1)+")",!t&&e.mark.snippet&&(n+="\n\n"+e.mark.snippet),i+" "+n):i}function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=i(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){return this.name+": "+i(this,e)};var o=r;function a(e,t,n,i,r){var o="",a="",l=Math.floor(r/2)-1;return i-t>l&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)})),n[t]=e})),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.Line truncated
|
||||
/*! js-yaml 4.1.1 https://github.com/nodeca/js-yaml @license MIT */
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;n<t;n+=1)i+=e;return i},isNegativeZero:function(e){return 0===e&&Number.NEGATIVE_INFINITY===1/e},extend:function(e,t){var n,i,r,o;if(t)for(n=0,i=(o=Object.keys(t)).length;n<i;n+=1)e[r=o[n]]=t[r];return e}};function i(e,t){var n="",i=e.reason||"(unknown reason)";return e.mark?(e.mark.name&&(n+='in "'+e.mark.name+'" '),n+="("+(e.mark.line+1)+":"+(e.mark.column+1)+")",!t&&e.mark.snippet&&(n+="\n\n"+e.mark.snippet),i+" "+n):i}function r(e,t){Error.call(this),this.name="YAMLException",this.reason=e,this.mark=t,this.message=i(this,!1),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack||""}r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r.prototype.toString=function(e){return this.name+": "+i(this,e)};var o=r;function a(e,t,n,i,r){var o="",a="",l=Math.floor(r/2)-1;return i-t>l&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach(function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')}),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach(function(n){e[n].forEach(function(e){t[String(e)]=n})}),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach(function(e){var t=n.length;n.forEach(function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)}),n[t]=e}),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach(function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")}),n.forEach(function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")});var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kiLine truncated
|
||||
+50
-44
@@ -1,49 +1,55 @@
|
||||
(function(){function diff_match_patch(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=0.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=0.5;this.Patch_Margin=4;this.Match_MaxBits=32}
|
||||
diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[[0,a]]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);var f=this.diff_commonSuffix(a,b),g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,b.length-f);a=this.diff_compute_(a,
|
||||
b,e,d);c&&a.unshift([0,c]);g&&a.push([0,g]);this.diff_cleanupMerge(a);return a};
|
||||
diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[[1,b]];if(!b)return[[-1,a]];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[[1,e.substring(0,g)],[0,f],[1,e.substring(g+f.length)]],a.length>b.length&&(c[0][0]=c[2][0]=-1),c):1==f.length?[[-1,a],[1,b]]:(e=this.diff_halfMatch_(a,b))?(f=e[0],a=e[1],g=e[2],b=e[3],e=e[4],f=this.diff_main(f,g,c,d),c=this.diff_main(a,b,c,d),f.concat([[0,e]],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,b,
|
||||
d):this.diff_bisect_(a,b,d)};
|
||||
diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b);a=d.chars1;b=d.chars2;d=d.lineArray;a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push([0,""]);for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case 1:e++;g+=a[b][1];break;case -1:d++;f+=a[b][1];break;case 0:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
|
||||
diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=f,h=2*f,j=Array(h),i=Array(h),k=0;k<h;k++)j[k]=-1,i[k]=-1;j[g+1]=0;i[g+1]=0;for(var k=d-e,q=0!=k%2,r=0,t=0,p=0,w=0,v=0;v<f&&!((new Date).getTime()>c);v++){for(var n=-v+r;n<=v-t;n+=2){var l=g+n,m;m=n==-v||n!=v&&j[l-1]<j[l+1]?j[l+1]:j[l-1]+1;for(var s=m-n;m<d&&s<e&&a.charAt(m)==b.charAt(s);)m++,s++;j[l]=m;if(m>d)t+=2;else if(s>e)r+=2;else if(q&&(l=g+k-n,0<=l&&l<h&&-1!=i[l])){var u=d-i[l];if(m>=
|
||||
u)return this.diff_bisectSplit_(a,b,m,s,c)}}for(n=-v+p;n<=v-w;n+=2){l=g+n;u=n==-v||n!=v&&i[l-1]<i[l+1]?i[l+1]:i[l-1]+1;for(m=u-n;u<d&&m<e&&a.charAt(d-u-1)==b.charAt(e-m-1);)u++,m++;i[l]=u;if(u>d)w+=2;else if(m>e)p+=2;else if(!q&&(l=g+k-n,0<=l&&(l<h&&-1!=j[l])&&(m=j[l],s=g+m-l,u=d-u,m>=u)))return this.diff_bisectSplit_(a,b,m,s,c)}}return[[-1,a],[1,b]]};
|
||||
var diff_match_patch=function(){this.Diff_Timeout=1;this.Diff_EditCost=4;this.Match_Threshold=.5;this.Match_Distance=1E3;this.Patch_DeleteThreshold=.5;this.Patch_Margin=4;this.Match_MaxBits=32},DIFF_DELETE=-1,DIFF_INSERT=1,DIFF_EQUAL=0;diff_match_patch.Diff=function(a,b){this[0]=a;this[1]=b};diff_match_patch.Diff.prototype.length=2;diff_match_patch.Diff.prototype.toString=function(){return this[0]+","+this[1]};
|
||||
diff_match_patch.prototype.diff_main=function(a,b,c,d){"undefined"==typeof d&&(d=0>=this.Diff_Timeout?Number.MAX_VALUE:(new Date).getTime()+1E3*this.Diff_Timeout);if(null==a||null==b)throw Error("Null input. (diff_main)");if(a==b)return a?[new diff_match_patch.Diff(DIFF_EQUAL,a)]:[];"undefined"==typeof c&&(c=!0);var e=c,f=this.diff_commonPrefix(a,b);c=a.substring(0,f);a=a.substring(f);b=b.substring(f);f=this.diff_commonSuffix(a,b);var g=a.substring(a.length-f);a=a.substring(0,a.length-f);b=b.substring(0,
|
||||
b.length-f);a=this.diff_compute_(a,b,e,d);c&&a.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c));g&&a.push(new diff_match_patch.Diff(DIFF_EQUAL,g));this.diff_cleanupMerge(a);return a};
|
||||
diff_match_patch.prototype.diff_compute_=function(a,b,c,d){if(!a)return[new diff_match_patch.Diff(DIFF_INSERT,b)];if(!b)return[new diff_match_patch.Diff(DIFF_DELETE,a)];var e=a.length>b.length?a:b,f=a.length>b.length?b:a,g=e.indexOf(f);return-1!=g?(c=[new diff_match_patch.Diff(DIFF_INSERT,e.substring(0,g)),new diff_match_patch.Diff(DIFF_EQUAL,f),new diff_match_patch.Diff(DIFF_INSERT,e.substring(g+f.length))],a.length>b.length&&(c[0][0]=c[2][0]=DIFF_DELETE),c):1==f.length?[new diff_match_patch.Diff(DIFF_DELETE,
|
||||
a),new diff_match_patch.Diff(DIFF_INSERT,b)]:(e=this.diff_halfMatch_(a,b))?(b=e[1],f=e[3],a=e[4],e=this.diff_main(e[0],e[2],c,d),c=this.diff_main(b,f,c,d),e.concat([new diff_match_patch.Diff(DIFF_EQUAL,a)],c)):c&&100<a.length&&100<b.length?this.diff_lineMode_(a,b,d):this.diff_bisect_(a,b,d)};
|
||||
diff_match_patch.prototype.diff_lineMode_=function(a,b,c){var d=this.diff_linesToChars_(a,b);a=d.chars1;b=d.chars2;d=d.lineArray;a=this.diff_main(a,b,!1,c);this.diff_charsToLines_(a,d);this.diff_cleanupSemantic(a);a.push(new diff_match_patch.Diff(DIFF_EQUAL,""));for(var e=d=b=0,f="",g="";b<a.length;){switch(a[b][0]){case DIFF_INSERT:e++;g+=a[b][1];break;case DIFF_DELETE:d++;f+=a[b][1];break;case DIFF_EQUAL:if(1<=d&&1<=e){a.splice(b-d-e,d+e);b=b-d-e;d=this.diff_main(f,g,!1,c);for(e=d.length-1;0<=e;e--)a.splice(b,
|
||||
0,d[e]);b+=d.length}d=e=0;g=f=""}b++}a.pop();return a};
|
||||
diff_match_patch.prototype.diff_bisect_=function(a,b,c){for(var d=a.length,e=b.length,f=Math.ceil((d+e)/2),g=2*f,h=Array(g),l=Array(g),k=0;k<g;k++)h[k]=-1,l[k]=-1;h[f+1]=0;l[f+1]=0;k=d-e;for(var m=0!=k%2,p=0,x=0,w=0,q=0,t=0;t<f&&!((new Date).getTime()>c);t++){for(var v=-t+p;v<=t-x;v+=2){var n=f+v;var r=v==-t||v!=t&&h[n-1]<h[n+1]?h[n+1]:h[n-1]+1;for(var y=r-v;r<d&&y<e&&a.charAt(r)==b.charAt(y);)r++,y++;h[n]=r;if(r>d)x+=2;else if(y>e)p+=2;else if(m&&(n=f+k-v,0<=n&&n<g&&-1!=l[n])){var u=d-l[n];if(r>=
|
||||
u)return this.diff_bisectSplit_(a,b,r,y,c)}}for(v=-t+w;v<=t-q;v+=2){n=f+v;u=v==-t||v!=t&&l[n-1]<l[n+1]?l[n+1]:l[n-1]+1;for(r=u-v;u<d&&r<e&&a.charAt(d-u-1)==b.charAt(e-r-1);)u++,r++;l[n]=u;if(u>d)q+=2;else if(r>e)w+=2;else if(!m&&(n=f+k-v,0<=n&&n<g&&-1!=h[n]&&(r=h[n],y=f+r-n,u=d-u,r>=u)))return this.diff_bisectSplit_(a,b,r,y,c)}}return[new diff_match_patch.Diff(DIFF_DELETE,a),new diff_match_patch.Diff(DIFF_INSERT,b)]};
|
||||
diff_match_patch.prototype.diff_bisectSplit_=function(a,b,c,d,e){var f=a.substring(0,c),g=b.substring(0,d);a=a.substring(c);b=b.substring(d);f=this.diff_main(f,g,!1,e);e=this.diff_main(a,b,!1,e);return f.concat(e)};
|
||||
diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,f=-1,g=d.length;f<a.length-1;){f=a.indexOf("\n",c);-1==f&&(f=a.length-1);var r=a.substring(c,f+1),c=f+1;(e.hasOwnProperty?e.hasOwnProperty(r):void 0!==e[r])?b+=String.fromCharCode(e[r]):(b+=String.fromCharCode(g),e[r]=g,d[g++]=r)}return b}var d=[],e={};d[0]="";var f=c(a),g=c(b);return{chars1:f,chars2:g,lineArray:d}};
|
||||
diff_match_patch.prototype.diff_linesToChars_=function(a,b){function c(a){for(var b="",c=0,g=-1,h=d.length;g<a.length-1;){g=a.indexOf("\n",c);-1==g&&(g=a.length-1);var l=a.substring(c,g+1);(e.hasOwnProperty?e.hasOwnProperty(l):void 0!==e[l])?b+=String.fromCharCode(e[l]):(h==f&&(l=a.substring(c),g=a.length),b+=String.fromCharCode(h),e[l]=h,d[h++]=l);c=g+1}return b}var d=[],e={};d[0]="";var f=4E4,g=c(a);f=65535;var h=c(b);return{chars1:g,chars2:h,lineArray:d}};
|
||||
diff_match_patch.prototype.diff_charsToLines_=function(a,b){for(var c=0;c<a.length;c++){for(var d=a[c][1],e=[],f=0;f<d.length;f++)e[f]=b[d.charCodeAt(f)];a[c][1]=e.join("")}};diff_match_patch.prototype.diff_commonPrefix=function(a,b){if(!a||!b||a.charAt(0)!=b.charAt(0))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(f,e)==b.substring(f,e)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
|
||||
diff_match_patch.prototype.diff_commonSuffix=function(a,b){if(!a||!b||a.charAt(a.length-1)!=b.charAt(b.length-1))return 0;for(var c=0,d=Math.min(a.length,b.length),e=d,f=0;c<e;)a.substring(a.length-e,a.length-f)==b.substring(b.length-e,b.length-f)?f=c=e:d=e,e=Math.floor((d-c)/2+c);return e};
|
||||
diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;for(var d=0,e=1;;){var f=a.substring(c-e),f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
|
||||
diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,j,n,l;-1!=(e=b.indexOf(d,e+1));){var m=f.diff_commonPrefix(a.substring(c),b.substring(e)),s=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<s+m&&(g=b.substring(e-s,e)+b.substring(e,e+m),h=a.substring(0,c-s),j=a.substring(c+m),n=b.substring(0,e-s),l=b.substring(e+m))}return 2*g.length>=a.length?[h,j,n,l,g]:null}if(0>=this.Diff_Timeout)return null;
|
||||
var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4)),d=c(d,e,Math.ceil(d.length/2)),h;if(!g&&!d)return null;h=d?g?g[4].length>d[4].length?g:d:d:g;var j;a.length>b.length?(g=h[0],d=h[1],e=h[2],j=h[3]):(e=h[0],j=h[1],g=h[2],d=h[3]);h=h[4];return[g,d,e,j,h]};
|
||||
diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,j=0,i=0;f<a.length;)0==a[f][0]?(c[d++]=f,g=j,h=i,i=j=0,e=a[f][1]):(1==a[f][0]?j+=a[f][1].length:i+=a[f][1].length,e&&(e.length<=Math.max(g,h)&&e.length<=Math.max(j,i))&&(a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,d--,f=0<d?c[d-1]:-1,i=j=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<a.length;){if(-1==a[f-1][0]&&1==a[f][0]){b=a[f-1][1];c=a[f][1];
|
||||
d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,[0,c.substring(0,d)]),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,[0,b.substring(0,e)]),a[f-1][0]=1,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=-1,a[f+1][1]=b.substring(e),f++;f++}f++}};
|
||||
diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_),c=g&&c.match(diff_match_patch.linebreakRegex_),d=h&&d.match(diff_match_patch.linebreakRegex_),i=c&&a.match(diff_match_patch.blanklineEndRegex_),j=d&&b.match(diff_match_patch.blanklineStartRegex_);
|
||||
return i||j?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(0==a[c-1][0]&&0==a[c+1][0]){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g)var h=e.substring(e.length-g),d=d.substring(0,d.length-g),e=h+e.substring(0,e.length-g),f=h+f;for(var g=d,h=e,j=f,i=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){var d=d+e.charAt(0),e=e.substring(1)+f.charAt(0),f=f.substring(1),k=b(d,e)+b(e,f);k>=i&&(i=k,g=d,h=e,j=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-1,1),c--),a[c][1]=
|
||||
h,j?a[c+1][1]=j:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
|
||||
diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,j=!1,i=!1;f<a.length;){if(0==a[f][0])a[f][1].length<this.Diff_EditCost&&(j||i)?(c[d++]=f,g=j,h=i,e=a[f][1]):(d=0,e=null),j=i=!1;else if(-1==a[f][0]?i=!0:j=!0,e&&(g&&h&&j&&i||e.length<this.Diff_EditCost/2&&3==g+h+j+i))a.splice(c[d-1],0,[-1,e]),a[c[d-1]+1][0]=1,d--,e=null,g&&h?(j=i=!0,d=0):(d--,f=0<d?c[d-1]:-1,j=i=!1),b=!0;f++}b&&this.diff_cleanupMerge(a)};
|
||||
diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push([0,""]);for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case 1:d++;f+=a[b][1];b++;break;case -1:c++;e+=a[b][1];b++;break;case 0:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&0==a[b-c-d-1][0]?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,[0,f.substring(0,g)]),b++),f=f.substring(g),e=e.substring(g)),g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-
|
||||
g),e=e.substring(0,e.length-g))),0===c?a.splice(b-d,c+d,[1,f]):0===d?a.splice(b-c,c+d,[-1,e]):a.splice(b-c-d,c+d,[-1,e],[1,f]),b=b-c-d+(c?1:0)+(d?1:0)+1):0!==b&&0==a[b-1][0]?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)0==a[b-1][0]&&0==a[b+1][0]&&(a[b][1].substring(a[b][1].length-a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,
|
||||
a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){1!==a[g][0]&&(c+=a[g][1].length);-1!==a[g][0]&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&-1===a[g][0]?f:f+(b-e)};
|
||||
diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],j=a[g][1],j=j.replace(c,"&").replace(d,"<").replace(e,">").replace(f,"¶<br>");switch(h){case 1:b[g]='<ins style="background:#e6ffe6;">'+j+"</ins>";break;case -1:b[g]='<del style="background:#ffe6e6;">'+j+"</del>";break;case 0:b[g]="<span>"+j+"</span>"}}return b.join("")};
|
||||
diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)-1!==a[c][0]&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][0],g=a[e][1];switch(f){case 1:c+=g.length;break;case -1:d+=g.length;break;case 0:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
|
||||
diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case 1:b[c]="+"+encodeURI(a[c][1]);break;case -1:b[c]="-"+a[c][1].length;break;case 0:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
|
||||
diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=[1,decodeURI(h)]}catch(j){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var i=parseInt(h,10);if(isNaN(i)||0>i)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=i);"="==f[g].charAt(0)?c[d++]=[0,h]:c[d++]=[-1,h];break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+
|
||||
f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
|
||||
diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return!f.Match_Distance?g?1:e:e+g/f.Match_Distance}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));for(var j=1<<b.length-1,h=-1,i,k,q=b.length+a.length,r,t=0;t<b.length;t++){i=0;for(k=q;i<k;)d(t,c+
|
||||
k)<=g?i=k:q=k,k=Math.floor((q-i)/2+i);q=k;i=Math.max(1,c-k+1);var p=Math.min(c+k,a.length)+b.length;k=Array(p+2);for(k[p+1]=(1<<t)-1;p>=i;p--){var w=e[a.charAt(p-1)];k[p]=0===t?(k[p+1]<<1|1)&w:(k[p+1]<<1|1)&w|((r[p+1]|r[p])<<1|1)|r[p+1];if(k[p]&j&&(w=d(t,p-1),w<=g))if(g=w,h=p-1,h>c)i=Math.max(1,2*c-h);else break}if(d(t+1,c)>g)break;r=k}return h};
|
||||
diff_match_patch.prototype.diff_commonOverlap_=function(a,b){var c=a.length,d=b.length;if(0==c||0==d)return 0;c>d?a=a.substring(c-d):c<d&&(b=b.substring(0,c));c=Math.min(c,d);if(a==b)return c;d=0;for(var e=1;;){var f=a.substring(c-e);f=b.indexOf(f);if(-1==f)return d;e+=f;if(0==f||a.substring(c-e)==b.substring(0,e))d=e,e++}};
|
||||
diff_match_patch.prototype.diff_halfMatch_=function(a,b){function c(a,b,c){for(var d=a.substring(c,c+Math.floor(a.length/4)),e=-1,g="",h,k,l,m;-1!=(e=b.indexOf(d,e+1));){var p=f.diff_commonPrefix(a.substring(c),b.substring(e)),u=f.diff_commonSuffix(a.substring(0,c),b.substring(0,e));g.length<u+p&&(g=b.substring(e-u,e)+b.substring(e,e+p),h=a.substring(0,c-u),k=a.substring(c+p),l=b.substring(0,e-u),m=b.substring(e+p))}return 2*g.length>=a.length?[h,k,l,m,g]:null}if(0>=this.Diff_Timeout)return null;
|
||||
var d=a.length>b.length?a:b,e=a.length>b.length?b:a;if(4>d.length||2*e.length<d.length)return null;var f=this,g=c(d,e,Math.ceil(d.length/4));d=c(d,e,Math.ceil(d.length/2));if(g||d)g=d?g?g[4].length>d[4].length?g:d:d:g;else return null;if(a.length>b.length){d=g[0];e=g[1];var h=g[2];var l=g[3]}else h=g[0],l=g[1],d=g[2],e=g[3];return[d,e,h,l,g[4]]};
|
||||
diff_match_patch.prototype.diff_cleanupSemantic=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=0,h=0,l=0,k=0;f<a.length;)a[f][0]==DIFF_EQUAL?(c[d++]=f,g=l,h=k,k=l=0,e=a[f][1]):(a[f][0]==DIFF_INSERT?l+=a[f][1].length:k+=a[f][1].length,e&&e.length<=Math.max(g,h)&&e.length<=Math.max(l,k)&&(a.splice(c[d-1],0,new diff_match_patch.Diff(DIFF_DELETE,e)),a[c[d-1]+1][0]=DIFF_INSERT,d--,d--,f=0<d?c[d-1]:-1,k=l=h=g=0,e=null,b=!0)),f++;b&&this.diff_cleanupMerge(a);this.diff_cleanupSemanticLossless(a);for(f=1;f<
|
||||
a.length;){if(a[f-1][0]==DIFF_DELETE&&a[f][0]==DIFF_INSERT){b=a[f-1][1];c=a[f][1];d=this.diff_commonOverlap_(b,c);e=this.diff_commonOverlap_(c,b);if(d>=e){if(d>=b.length/2||d>=c.length/2)a.splice(f,0,new diff_match_patch.Diff(DIFF_EQUAL,c.substring(0,d))),a[f-1][1]=b.substring(0,b.length-d),a[f+1][1]=c.substring(d),f++}else if(e>=b.length/2||e>=c.length/2)a.splice(f,0,new diff_match_patch.Diff(DIFF_EQUAL,b.substring(0,e))),a[f-1][0]=DIFF_INSERT,a[f-1][1]=c.substring(0,c.length-e),a[f+1][0]=DIFF_DELETE,
|
||||
a[f+1][1]=b.substring(e),f++;f++}f++}};
|
||||
diff_match_patch.prototype.diff_cleanupSemanticLossless=function(a){function b(a,b){if(!a||!b)return 6;var c=a.charAt(a.length-1),d=b.charAt(0),e=c.match(diff_match_patch.nonAlphaNumericRegex_),f=d.match(diff_match_patch.nonAlphaNumericRegex_),g=e&&c.match(diff_match_patch.whitespaceRegex_),h=f&&d.match(diff_match_patch.whitespaceRegex_);c=g&&c.match(diff_match_patch.linebreakRegex_);d=h&&d.match(diff_match_patch.linebreakRegex_);var k=c&&a.match(diff_match_patch.blanklineEndRegex_),l=d&&b.match(diff_match_patch.blanklineStartRegex_);
|
||||
return k||l?5:c||d?4:e&&!g&&h?3:g||h?2:e||f?1:0}for(var c=1;c<a.length-1;){if(a[c-1][0]==DIFF_EQUAL&&a[c+1][0]==DIFF_EQUAL){var d=a[c-1][1],e=a[c][1],f=a[c+1][1],g=this.diff_commonSuffix(d,e);if(g){var h=e.substring(e.length-g);d=d.substring(0,d.length-g);e=h+e.substring(0,e.length-g);f=h+f}g=d;h=e;for(var l=f,k=b(d,e)+b(e,f);e.charAt(0)===f.charAt(0);){d+=e.charAt(0);e=e.substring(1)+f.charAt(0);f=f.substring(1);var m=b(d,e)+b(e,f);m>=k&&(k=m,g=d,h=e,l=f)}a[c-1][1]!=g&&(g?a[c-1][1]=g:(a.splice(c-
|
||||
1,1),c--),a[c][1]=h,l?a[c+1][1]=l:(a.splice(c+1,1),c--))}c++}};diff_match_patch.nonAlphaNumericRegex_=/[^a-zA-Z0-9]/;diff_match_patch.whitespaceRegex_=/\s/;diff_match_patch.linebreakRegex_=/[\r\n]/;diff_match_patch.blanklineEndRegex_=/\n\r?\n$/;diff_match_patch.blanklineStartRegex_=/^\r?\n\r?\n/;
|
||||
diff_match_patch.prototype.diff_cleanupEfficiency=function(a){for(var b=!1,c=[],d=0,e=null,f=0,g=!1,h=!1,l=!1,k=!1;f<a.length;)a[f][0]==DIFF_EQUAL?(a[f][1].length<this.Diff_EditCost&&(l||k)?(c[d++]=f,g=l,h=k,e=a[f][1]):(d=0,e=null),l=k=!1):(a[f][0]==DIFF_DELETE?k=!0:l=!0,e&&(g&&h&&l&&k||e.length<this.Diff_EditCost/2&&3==g+h+l+k)&&(a.splice(c[d-1],0,new diff_match_patch.Diff(DIFF_DELETE,e)),a[c[d-1]+1][0]=DIFF_INSERT,d--,e=null,g&&h?(l=k=!0,d=0):(d--,f=0<d?c[d-1]:-1,l=k=!1),b=!0)),f++;b&&this.diff_cleanupMerge(a)};
|
||||
diff_match_patch.prototype.diff_cleanupMerge=function(a){a.push(new diff_match_patch.Diff(DIFF_EQUAL,""));for(var b=0,c=0,d=0,e="",f="",g;b<a.length;)switch(a[b][0]){case DIFF_INSERT:d++;f+=a[b][1];b++;break;case DIFF_DELETE:c++;e+=a[b][1];b++;break;case DIFF_EQUAL:1<c+d?(0!==c&&0!==d&&(g=this.diff_commonPrefix(f,e),0!==g&&(0<b-c-d&&a[b-c-d-1][0]==DIFF_EQUAL?a[b-c-d-1][1]+=f.substring(0,g):(a.splice(0,0,new diff_match_patch.Diff(DIFF_EQUAL,f.substring(0,g))),b++),f=f.substring(g),e=e.substring(g)),
|
||||
g=this.diff_commonSuffix(f,e),0!==g&&(a[b][1]=f.substring(f.length-g)+a[b][1],f=f.substring(0,f.length-g),e=e.substring(0,e.length-g))),b-=c+d,a.splice(b,c+d),e.length&&(a.splice(b,0,new diff_match_patch.Diff(DIFF_DELETE,e)),b++),f.length&&(a.splice(b,0,new diff_match_patch.Diff(DIFF_INSERT,f)),b++),b++):0!==b&&a[b-1][0]==DIFF_EQUAL?(a[b-1][1]+=a[b][1],a.splice(b,1)):b++,c=d=0,f=e=""}""===a[a.length-1][1]&&a.pop();c=!1;for(b=1;b<a.length-1;)a[b-1][0]==DIFF_EQUAL&&a[b+1][0]==DIFF_EQUAL&&(a[b][1].substring(a[b][1].length-
|
||||
a[b-1][1].length)==a[b-1][1]?(a[b][1]=a[b-1][1]+a[b][1].substring(0,a[b][1].length-a[b-1][1].length),a[b+1][1]=a[b-1][1]+a[b+1][1],a.splice(b-1,1),c=!0):a[b][1].substring(0,a[b+1][1].length)==a[b+1][1]&&(a[b-1][1]+=a[b+1][1],a[b][1]=a[b][1].substring(a[b+1][1].length)+a[b+1][1],a.splice(b+1,1),c=!0)),b++;c&&this.diff_cleanupMerge(a)};
|
||||
diff_match_patch.prototype.diff_xIndex=function(a,b){var c=0,d=0,e=0,f=0,g;for(g=0;g<a.length;g++){a[g][0]!==DIFF_INSERT&&(c+=a[g][1].length);a[g][0]!==DIFF_DELETE&&(d+=a[g][1].length);if(c>b)break;e=c;f=d}return a.length!=g&&a[g][0]===DIFF_DELETE?f:f+(b-e)};
|
||||
diff_match_patch.prototype.diff_prettyHtml=function(a){for(var b=[],c=/&/g,d=/</g,e=/>/g,f=/\n/g,g=0;g<a.length;g++){var h=a[g][0],l=a[g][1].replace(c,"&").replace(d,"<").replace(e,">").replace(f,"¶<br>");switch(h){case DIFF_INSERT:b[g]='<ins style="background:#e6ffe6;">'+l+"</ins>";break;case DIFF_DELETE:b[g]='<del style="background:#ffe6e6;">'+l+"</del>";break;case DIFF_EQUAL:b[g]="<span>"+l+"</span>"}}return b.join("")};
|
||||
diff_match_patch.prototype.diff_text1=function(a){for(var b=[],c=0;c<a.length;c++)a[c][0]!==DIFF_INSERT&&(b[c]=a[c][1]);return b.join("")};diff_match_patch.prototype.diff_text2=function(a){for(var b=[],c=0;c<a.length;c++)a[c][0]!==DIFF_DELETE&&(b[c]=a[c][1]);return b.join("")};
|
||||
diff_match_patch.prototype.diff_levenshtein=function(a){for(var b=0,c=0,d=0,e=0;e<a.length;e++){var f=a[e][1];switch(a[e][0]){case DIFF_INSERT:c+=f.length;break;case DIFF_DELETE:d+=f.length;break;case DIFF_EQUAL:b+=Math.max(c,d),d=c=0}}return b+=Math.max(c,d)};
|
||||
diff_match_patch.prototype.diff_toDelta=function(a){for(var b=[],c=0;c<a.length;c++)switch(a[c][0]){case DIFF_INSERT:b[c]="+"+encodeURI(a[c][1]);break;case DIFF_DELETE:b[c]="-"+a[c][1].length;break;case DIFF_EQUAL:b[c]="="+a[c][1].length}return b.join("\t").replace(/%20/g," ")};
|
||||
diff_match_patch.prototype.diff_fromDelta=function(a,b){for(var c=[],d=0,e=0,f=b.split(/\t/g),g=0;g<f.length;g++){var h=f[g].substring(1);switch(f[g].charAt(0)){case "+":try{c[d++]=new diff_match_patch.Diff(DIFF_INSERT,decodeURI(h))}catch(k){throw Error("Illegal escape in diff_fromDelta: "+h);}break;case "-":case "=":var l=parseInt(h,10);if(isNaN(l)||0>l)throw Error("Invalid number in diff_fromDelta: "+h);h=a.substring(e,e+=l);"="==f[g].charAt(0)?c[d++]=new diff_match_patch.Diff(DIFF_EQUAL,h):c[d++]=
|
||||
new diff_match_patch.Diff(DIFF_DELETE,h);break;default:if(f[g])throw Error("Invalid diff operation in diff_fromDelta: "+f[g]);}}if(e!=a.length)throw Error("Delta length ("+e+") does not equal source text length ("+a.length+").");return c};diff_match_patch.prototype.match_main=function(a,b,c){if(null==a||null==b||null==c)throw Error("Null input. (match_main)");c=Math.max(0,Math.min(c,a.length));return a==b?0:a.length?a.substring(c,c+b.length)==b?c:this.match_bitap_(a,b,c):-1};
|
||||
diff_match_patch.prototype.match_bitap_=function(a,b,c){function d(a,d){var e=a/b.length,g=Math.abs(c-d);return f.Match_Distance?e+g/f.Match_Distance:g?1:e}if(b.length>this.Match_MaxBits)throw Error("Pattern too long for this browser.");var e=this.match_alphabet_(b),f=this,g=this.Match_Threshold,h=a.indexOf(b,c);-1!=h&&(g=Math.min(d(0,h),g),h=a.lastIndexOf(b,c+b.length),-1!=h&&(g=Math.min(d(0,h),g)));var l=1<<b.length-1;h=-1;for(var k,m,p=b.length+a.length,x,w=0;w<b.length;w++){k=0;for(m=p;k<m;)d(w,
|
||||
c+m)<=g?k=m:p=m,m=Math.floor((p-k)/2+k);p=m;k=Math.max(1,c-m+1);var q=Math.min(c+m,a.length)+b.length;m=Array(q+2);for(m[q+1]=(1<<w)-1;q>=k;q--){var t=e[a.charAt(q-1)];m[q]=0===w?(m[q+1]<<1|1)&t:(m[q+1]<<1|1)&t|(x[q+1]|x[q])<<1|1|x[q+1];if(m[q]&l&&(t=d(w,q-1),t<=g))if(g=t,h=q-1,h>c)k=Math.max(1,2*c-h);else break}if(d(w+1,c)>g)break;x=m}return h};
|
||||
diff_match_patch.prototype.match_alphabet_=function(a){for(var b={},c=0;c<a.length;c++)b[a.charAt(c)]=0;for(c=0;c<a.length;c++)b[a.charAt(c)]|=1<<a.length-c-1;return b};
|
||||
diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift([0,c]);(d=b.substring(a.start2+a.length1,a.start2+a.length1+d))&&a.diffs.push([0,d]);a.start1-=c.length;a.start2-=c.length;a.length1+=
|
||||
c.length+d.length;a.length2+=c.length+d.length}};
|
||||
diff_match_patch.prototype.patch_make=function(a,b,c){var d;if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c)d=a,b=this.diff_main(d,b,!0),2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b));else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
|
||||
if(0===b.length)return[];c=[];a=new diff_match_patch.patch_obj;for(var e=0,f=0,g=0,h=d,j=0;j<b.length;j++){var i=b[j][0],k=b[j][1];!e&&0!==i&&(a.start1=f,a.start2=g);switch(i){case 1:a.diffs[e++]=b[j];a.length2+=k.length;d=d.substring(0,g)+k+d.substring(g);break;case -1:a.length1+=k.length;a.diffs[e++]=b[j];d=d.substring(0,g)+d.substring(g+k.length);break;case 0:k.length<=2*this.Patch_Margin&&e&&b.length!=j+1?(a.diffs[e++]=b[j],a.length1+=k.length,a.length2+=k.length):k.length>=2*this.Patch_Margin&&
|
||||
e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}1!==i&&(f+=k.length);-1!==i&&(g+=k.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=d.diffs[f].slice();e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
|
||||
diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];a=this.patch_deepCopy(a);var c=this.patch_addPadding(a);b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),j,i=-1;if(h.length>this.Match_MaxBits){if(j=this.match_main(b,h.substring(0,this.Match_MaxBits),g),-1!=j&&(i=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==i||j>=i))j=-1}else j=this.match_main(b,h,g);
|
||||
if(-1==j)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=j-g,g=-1==i?b.substring(j,j+h.length):b.substring(j,i+this.Match_MaxBits),h==g)b=b.substring(0,j)+this.diff_text2(a[f].diffs)+b.substring(j+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);for(var h=0,k,i=0;i<a[f].diffs.length;i++){var q=a[f].diffs[i];0!==q[0]&&(k=this.diff_xIndex(g,h));1===q[0]?b=b.substring(0,
|
||||
j+k)+q[1]+b.substring(j+k):-1===q[0]&&(b=b.substring(0,j+k)+b.substring(j+this.diff_xIndex(g,h+q[1].length)));-1!==q[0]&&(h+=q[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
|
||||
diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;var d=a[0],e=d.diffs;if(0==e.length||0!=e[0][0])e.unshift([0,c]),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;0==e.length||0!=e[e.length-1][0]?(e.push([0,
|
||||
c]),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
|
||||
diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,j=!0;h.start1=e-g.length;h.start2=f-g.length;""!==g&&(h.length1=h.length2=g.length,h.diffs.push([0,g]));for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){var g=d.diffs[0][0],i=d.diffs[0][1];1===g?(h.length2+=i.length,f+=i.length,h.diffs.push(d.diffs.shift()),
|
||||
j=!1):-1===g&&1==h.diffs.length&&0==h.diffs[0][0]&&i.length>2*b?(h.length1+=i.length,e+=i.length,j=!1,h.diffs.push([g,i]),d.diffs.shift()):(i=i.substring(0,b-h.length1-this.Patch_Margin),h.length1+=i.length,e+=i.length,0===g?(h.length2+=i.length,f+=i.length):j=!1,h.diffs.push([g,i]),i==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(i.length))}g=this.diff_text2(h.diffs);g=g.substring(g.length-this.Patch_Margin);i=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==i&&
|
||||
(h.length1+=i.length,h.length2+=i.length,0!==h.diffs.length&&0===h.diffs[h.diffs.length-1][0]?h.diffs[h.diffs.length-1][1]+=i:h.diffs.push([0,i]));j||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
|
||||
diff_match_patch.prototype.patch_addContext_=function(a,b){if(0!=b.length){if(null===a.start2)throw Error("patch not initialized");for(var c=b.substring(a.start2,a.start2+a.length1),d=0;b.indexOf(c)!=b.lastIndexOf(c)&&c.length<this.Match_MaxBits-this.Patch_Margin-this.Patch_Margin;)d+=this.Patch_Margin,c=b.substring(a.start2-d,a.start2+a.length1+d);d+=this.Patch_Margin;(c=b.substring(a.start2-d,a.start2))&&a.diffs.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c));(d=b.substring(a.start2+a.length1,
|
||||
a.start2+a.length1+d))&&a.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,d));a.start1-=c.length;a.start2-=c.length;a.length1+=c.length+d.length;a.length2+=c.length+d.length}};
|
||||
diff_match_patch.prototype.patch_make=function(a,b,c){if("string"==typeof a&&"string"==typeof b&&"undefined"==typeof c){var d=a;b=this.diff_main(d,b,!0);2<b.length&&(this.diff_cleanupSemantic(b),this.diff_cleanupEfficiency(b))}else if(a&&"object"==typeof a&&"undefined"==typeof b&&"undefined"==typeof c)b=a,d=this.diff_text1(b);else if("string"==typeof a&&b&&"object"==typeof b&&"undefined"==typeof c)d=a;else if("string"==typeof a&&"string"==typeof b&&c&&"object"==typeof c)d=a,b=c;else throw Error("Unknown call format to patch_make.");
|
||||
if(0===b.length)return[];c=[];a=new diff_match_patch.patch_obj;for(var e=0,f=0,g=0,h=d,l=0;l<b.length;l++){var k=b[l][0],m=b[l][1];e||k===DIFF_EQUAL||(a.start1=f,a.start2=g);switch(k){case DIFF_INSERT:a.diffs[e++]=b[l];a.length2+=m.length;d=d.substring(0,g)+m+d.substring(g);break;case DIFF_DELETE:a.length1+=m.length;a.diffs[e++]=b[l];d=d.substring(0,g)+d.substring(g+m.length);break;case DIFF_EQUAL:m.length<=2*this.Patch_Margin&&e&&b.length!=l+1?(a.diffs[e++]=b[l],a.length1+=m.length,a.length2+=m.length):
|
||||
m.length>=2*this.Patch_Margin&&e&&(this.patch_addContext_(a,h),c.push(a),a=new diff_match_patch.patch_obj,e=0,h=d,f=g)}k!==DIFF_INSERT&&(f+=m.length);k!==DIFF_DELETE&&(g+=m.length)}e&&(this.patch_addContext_(a,h),c.push(a));return c};
|
||||
diff_match_patch.prototype.patch_deepCopy=function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c],e=new diff_match_patch.patch_obj;e.diffs=[];for(var f=0;f<d.diffs.length;f++)e.diffs[f]=new diff_match_patch.Diff(d.diffs[f][0],d.diffs[f][1]);e.start1=d.start1;e.start2=d.start2;e.length1=d.length1;e.length2=d.length2;b[c]=e}return b};
|
||||
diff_match_patch.prototype.patch_apply=function(a,b){if(0==a.length)return[b,[]];a=this.patch_deepCopy(a);var c=this.patch_addPadding(a);b=c+b+c;this.patch_splitMax(a);for(var d=0,e=[],f=0;f<a.length;f++){var g=a[f].start2+d,h=this.diff_text1(a[f].diffs),l=-1;if(h.length>this.Match_MaxBits){var k=this.match_main(b,h.substring(0,this.Match_MaxBits),g);-1!=k&&(l=this.match_main(b,h.substring(h.length-this.Match_MaxBits),g+h.length-this.Match_MaxBits),-1==l||k>=l)&&(k=-1)}else k=this.match_main(b,h,
|
||||
g);if(-1==k)e[f]=!1,d-=a[f].length2-a[f].length1;else if(e[f]=!0,d=k-g,g=-1==l?b.substring(k,k+h.length):b.substring(k,l+this.Match_MaxBits),h==g)b=b.substring(0,k)+this.diff_text2(a[f].diffs)+b.substring(k+h.length);else if(g=this.diff_main(h,g,!1),h.length>this.Match_MaxBits&&this.diff_levenshtein(g)/h.length>this.Patch_DeleteThreshold)e[f]=!1;else{this.diff_cleanupSemanticLossless(g);h=0;var m;for(l=0;l<a[f].diffs.length;l++){var p=a[f].diffs[l];p[0]!==DIFF_EQUAL&&(m=this.diff_xIndex(g,h));p[0]===
|
||||
DIFF_INSERT?b=b.substring(0,k+m)+p[1]+b.substring(k+m):p[0]===DIFF_DELETE&&(b=b.substring(0,k+m)+b.substring(k+this.diff_xIndex(g,h+p[1].length)));p[0]!==DIFF_DELETE&&(h+=p[1].length)}}}b=b.substring(c.length,b.length-c.length);return[b,e]};
|
||||
diff_match_patch.prototype.patch_addPadding=function(a){for(var b=this.Patch_Margin,c="",d=1;d<=b;d++)c+=String.fromCharCode(d);for(d=0;d<a.length;d++)a[d].start1+=b,a[d].start2+=b;d=a[0];var e=d.diffs;if(0==e.length||e[0][0]!=DIFF_EQUAL)e.unshift(new diff_match_patch.Diff(DIFF_EQUAL,c)),d.start1-=b,d.start2-=b,d.length1+=b,d.length2+=b;else if(b>e[0][1].length){var f=b-e[0][1].length;e[0][1]=c.substring(e[0][1].length)+e[0][1];d.start1-=f;d.start2-=f;d.length1+=f;d.length2+=f}d=a[a.length-1];e=d.diffs;
|
||||
0==e.length||e[e.length-1][0]!=DIFF_EQUAL?(e.push(new diff_match_patch.Diff(DIFF_EQUAL,c)),d.length1+=b,d.length2+=b):b>e[e.length-1][1].length&&(f=b-e[e.length-1][1].length,e[e.length-1][1]+=c.substring(0,f),d.length1+=f,d.length2+=f);return c};
|
||||
diff_match_patch.prototype.patch_splitMax=function(a){for(var b=this.Match_MaxBits,c=0;c<a.length;c++)if(!(a[c].length1<=b)){var d=a[c];a.splice(c--,1);for(var e=d.start1,f=d.start2,g="";0!==d.diffs.length;){var h=new diff_match_patch.patch_obj,l=!0;h.start1=e-g.length;h.start2=f-g.length;""!==g&&(h.length1=h.length2=g.length,h.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,g)));for(;0!==d.diffs.length&&h.length1<b-this.Patch_Margin;){g=d.diffs[0][0];var k=d.diffs[0][1];g===DIFF_INSERT?(h.length2+=
|
||||
k.length,f+=k.length,h.diffs.push(d.diffs.shift()),l=!1):g===DIFF_DELETE&&1==h.diffs.length&&h.diffs[0][0]==DIFF_EQUAL&&k.length>2*b?(h.length1+=k.length,e+=k.length,l=!1,h.diffs.push(new diff_match_patch.Diff(g,k)),d.diffs.shift()):(k=k.substring(0,b-h.length1-this.Patch_Margin),h.length1+=k.length,e+=k.length,g===DIFF_EQUAL?(h.length2+=k.length,f+=k.length):l=!1,h.diffs.push(new diff_match_patch.Diff(g,k)),k==d.diffs[0][1]?d.diffs.shift():d.diffs[0][1]=d.diffs[0][1].substring(k.length))}g=this.diff_text2(h.diffs);
|
||||
g=g.substring(g.length-this.Patch_Margin);k=this.diff_text1(d.diffs).substring(0,this.Patch_Margin);""!==k&&(h.length1+=k.length,h.length2+=k.length,0!==h.diffs.length&&h.diffs[h.diffs.length-1][0]===DIFF_EQUAL?h.diffs[h.diffs.length-1][1]+=k:h.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,k)));l||a.splice(++c,0,h)}}};diff_match_patch.prototype.patch_toText=function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b.join("")};
|
||||
diff_match_patch.prototype.patch_fromText=function(a){var b=[];if(!a)return b;a=a.split("\n");for(var c=0,d=/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@$/;c<a.length;){var e=a[c].match(d);if(!e)throw Error("Invalid patch string: "+a[c]);var f=new diff_match_patch.patch_obj;b.push(f);f.start1=parseInt(e[1],10);""===e[2]?(f.start1--,f.length1=1):"0"==e[2]?f.length1=0:(f.start1--,f.length1=parseInt(e[2],10));f.start2=parseInt(e[3],10);""===e[4]?(f.start2--,f.length2=1):"0"==e[4]?f.length2=0:(f.start2--,f.length2=
|
||||
parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push([-1,g]);else if("+"==e)f.diffs.push([1,g]);else if(" "==e)f.diffs.push([0,g]);else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
|
||||
diff_match_patch.patch_obj.prototype.toString=function(){var a,b;a=0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1;b=0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2;a=["@@ -"+a+" +"+b+" @@\n"];var c;for(b=0;b<this.diffs.length;b++){switch(this.diffs[b][0]){case 1:c="+";break;case -1:c="-";break;case 0:c=" "}a[b+1]=c+encodeURI(this.diffs[b][1])+"\n"}return a.join("").replace(/%20/g," ")};
|
||||
this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=-1;this.DIFF_INSERT=1;this.DIFF_EQUAL=0;})()
|
||||
parseInt(e[4],10));for(c++;c<a.length;){e=a[c].charAt(0);try{var g=decodeURI(a[c].substring(1))}catch(h){throw Error("Illegal escape in patch_fromText: "+g);}if("-"==e)f.diffs.push(new diff_match_patch.Diff(DIFF_DELETE,g));else if("+"==e)f.diffs.push(new diff_match_patch.Diff(DIFF_INSERT,g));else if(" "==e)f.diffs.push(new diff_match_patch.Diff(DIFF_EQUAL,g));else if("@"==e)break;else if(""!==e)throw Error('Invalid patch mode "'+e+'" in: '+g);c++}}return b};
|
||||
diff_match_patch.patch_obj=function(){this.diffs=[];this.start2=this.start1=null;this.length2=this.length1=0};
|
||||
diff_match_patch.patch_obj.prototype.toString=function(){for(var a=["@@ -"+(0===this.length1?this.start1+",0":1==this.length1?this.start1+1:this.start1+1+","+this.length1)+" +"+(0===this.length2?this.start2+",0":1==this.length2?this.start2+1:this.start2+1+","+this.length2)+" @@\n"],b,c=0;c<this.diffs.length;c++){switch(this.diffs[c][0]){case DIFF_INSERT:b="+";break;case DIFF_DELETE:b="-";break;case DIFF_EQUAL:b=" "}a[c+1]=b+encodeURI(this.diffs[c][1])+"\n"}return a.join("").replace(/%20/g," ")};
|
||||
this.diff_match_patch=diff_match_patch;this.DIFF_DELETE=DIFF_DELETE;this.DIFF_INSERT=DIFF_INSERT;this.DIFF_EQUAL=DIFF_EQUAL;
|
||||
@@ -166,7 +166,7 @@
|
||||
function copyObj(obj, target, overwrite) {
|
||||
if (!target) { target = {}; }
|
||||
for (var prop in obj)
|
||||
{ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
|
||||
{ if (Object.prototype.hasOwnProperty.call(obj, prop) && (overwrite !== false || !Object.prototype.hasOwnProperty.call(target, prop)))
|
||||
{ target[prop] = obj[prop]; } }
|
||||
return target
|
||||
}
|
||||
@@ -4426,7 +4426,7 @@
|
||||
// The element in which the editor lives.
|
||||
d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
||||
// See #6982. FIXME remove when this has been fixed for a while in Chrome
|
||||
if (chrome && chrome_version >= 105) { d.wrapper.style.clipPath = "inset(0px)"; }
|
||||
if (chrome && chrome_version === 105) { d.wrapper.style.clipPath = "inset(0px)"; }
|
||||
|
||||
// This attribute is respected by automatic translation systems such as Google Translate,
|
||||
// and may also be respected by tools used by human translators.
|
||||
@@ -9877,7 +9877,7 @@
|
||||
|
||||
addLegacyProps(CodeMirror);
|
||||
|
||||
CodeMirror.version = "5.65.18";
|
||||
CodeMirror.version = "5.65.21";
|
||||
|
||||
return CodeMirror;
|
||||
|
||||
|
||||
Reference in new issue
Block a user