Fix Xray config subscription visibility
This commit is contained in:
@@ -358,7 +358,7 @@ SING_BOX_URLTEST_DEFAULT_IDLE_TIMEOUT="30m"
|
||||
SERVER_COUNTRY_METHOD_FLAG_EMOJI="flag_emoji"
|
||||
SERVER_COUNTRY_METHOD_COUNTRY_IS="country_is"
|
||||
PODKOP_RELOAD_STATE_FORMAT=1
|
||||
PODKOP_RUNTIME_CACHE_FORMAT=5
|
||||
PODKOP_RUNTIME_CACHE_FORMAT=6
|
||||
PODKOP_RUNTIME_STABLE_MIN_AGE=2
|
||||
PODKOP_SYSTEM_INFO_CACHE_TTL=3600
|
||||
PODKOP_SUBSCRIPTION_UPDATE_JOB_FINISHED_TTL_MINUTES=60
|
||||
|
||||
@@ -640,6 +640,17 @@ sing_box_cf_subscription_prepared_slice() {
|
||||
sing_box_cf_ucode_input prepared-slice "$prepared_json" "$start" "$end" 2>/dev/null
|
||||
}
|
||||
|
||||
sing_box_cf_prepared_visible_count() {
|
||||
local prepared_json="$1"
|
||||
local count
|
||||
|
||||
count="$(sing_box_cf_ucode_input prepared-visible-count "$prepared_json" 2>/dev/null)"
|
||||
case "$count" in
|
||||
'' | *[!0-9]*) printf '0\n' ;;
|
||||
*) printf '%s\n' "$count" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
sing_box_cf_prepared_field_to_file() {
|
||||
local prepared_json="$1"
|
||||
local field="$2"
|
||||
@@ -785,8 +796,9 @@ sing_box_cf_apply_subscription_batch() {
|
||||
fi
|
||||
rm -f "$new_outbounds_tmp"
|
||||
|
||||
SUBSCRIPTION_OUTBOUND_COUNT="$new_outbounds_count"
|
||||
sing_box_cf_load_prepared_state "$prepared_json" || return 1
|
||||
SUBSCRIPTION_OUTBOUND_COUNT="$(sing_box_cf_tags_json_count "$SUBSCRIPTION_OUTBOUND_TAGS_JSON")"
|
||||
[ "${SUBSCRIPTION_OUTBOUND_COUNT:-0}" -gt 0 ] || return 1
|
||||
SING_BOX_CF_LAST_CONFIG="$SING_BOX_CF_VALIDATED_CONFIG"
|
||||
|
||||
return 0
|
||||
@@ -795,7 +807,7 @@ sing_box_cf_apply_subscription_batch() {
|
||||
sing_box_cf_apply_subscription_outbounds_range() {
|
||||
local start="$1"
|
||||
local count="$2"
|
||||
local end chunk outbounds_json display_name half rest index
|
||||
local end chunk outbounds_json display_name half rest index visible_count
|
||||
|
||||
[ "$count" -gt 0 ] || return 0
|
||||
|
||||
@@ -817,7 +829,8 @@ sing_box_cf_apply_subscription_outbounds_range() {
|
||||
log "Failed to append subscription metadata for rule '$SING_BOX_CF_SOURCE_SECTION'. Aborted." "fatal"
|
||||
exit 1
|
||||
fi
|
||||
SING_BOX_CF_FALLBACK_ADDED_COUNT=$((SING_BOX_CF_FALLBACK_ADDED_COUNT + count))
|
||||
visible_count="$(sing_box_cf_prepared_visible_count "$chunk")"
|
||||
SING_BOX_CF_FALLBACK_ADDED_COUNT=$((SING_BOX_CF_FALLBACK_ADDED_COUNT + visible_count))
|
||||
return 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -401,6 +401,21 @@ function supported_transport_type(transport) {
|
||||
transport == "httpupgrade" || transport == "xhttp" || transport == "kcp";
|
||||
}
|
||||
|
||||
function internal_flag(value) {
|
||||
if (value === true)
|
||||
return true;
|
||||
value = lc(as_string(value));
|
||||
return value == "1" || value == "true" || value == "yes" || value == "on";
|
||||
}
|
||||
|
||||
function outbound_is_hidden(outbound) {
|
||||
return type(outbound) == "object" && internal_flag(outbound.__podkop_hidden);
|
||||
}
|
||||
|
||||
function outbound_allows_group_type(outbound) {
|
||||
return type(outbound) == "object" && internal_flag(outbound.__podkop_allow_group);
|
||||
}
|
||||
|
||||
let supported_shadowsocks_methods = {
|
||||
"none": true,
|
||||
"aes-128-gcm": true,
|
||||
@@ -441,6 +456,8 @@ function prefilter_skip_reason(outbound, supports_xhttp, plugin_supports) {
|
||||
let proxy_type = as_string(outbound.type || "");
|
||||
if (proxy_type == "")
|
||||
return "missing type";
|
||||
if ((proxy_type == "selector" || proxy_type == "urltest") && outbound_allows_group_type(outbound))
|
||||
return "";
|
||||
if (proxy_type == "direct" || proxy_type == "selector" || proxy_type == "urltest" ||
|
||||
proxy_type == "dns" || proxy_type == "block")
|
||||
return "non-proxy outbound type: " + proxy_type;
|
||||
@@ -503,12 +520,33 @@ function unique_tag(base, taken) {
|
||||
function copy_outbound(outbound) {
|
||||
let copy = {};
|
||||
for (let key, value in outbound) {
|
||||
if (key != "tag" && key != "remark" && key != "share_link")
|
||||
if (key != "tag" && key != "remark" && key != "share_link" &&
|
||||
key != "__podkop_hidden" && key != "__podkop_allow_group")
|
||||
copy[key] = value;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
function rewrite_prepared_outbound_references(outbounds, tag_map) {
|
||||
for (let outbound in outbounds) {
|
||||
if (type(outbound) != "object")
|
||||
continue;
|
||||
|
||||
let detour = as_string(outbound.detour || "");
|
||||
if (detour != "" && tag_map[detour])
|
||||
outbound.detour = tag_map[detour];
|
||||
|
||||
if (type(outbound.outbounds) == "array") {
|
||||
let rewritten = [];
|
||||
for (let tag in outbound.outbounds) {
|
||||
tag = as_string(tag);
|
||||
push(rewritten, tag_map[tag] || tag);
|
||||
}
|
||||
outbound.outbounds = rewritten;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function candidate_outbounds(path) {
|
||||
let subscription = object_or_empty(read_json_file(path));
|
||||
let result = [];
|
||||
@@ -521,7 +559,11 @@ function candidate_outbounds(path) {
|
||||
};
|
||||
|
||||
for (let outbound in array_or_empty(subscription.outbounds)) {
|
||||
if (type(outbound) == "object" && !skipped_types[outbound.type])
|
||||
if (type(outbound) != "object")
|
||||
continue;
|
||||
if ((outbound.type == "selector" || outbound.type == "urltest") && outbound_allows_group_type(outbound))
|
||||
push(result, outbound);
|
||||
else if (!skipped_types[outbound.type])
|
||||
push(result, outbound);
|
||||
}
|
||||
|
||||
@@ -548,9 +590,11 @@ function prepare_subscription(config_path, outbounds_path, output_path, supports
|
||||
let servers = [];
|
||||
let links = [];
|
||||
let source_indices = [];
|
||||
let visible = [];
|
||||
let skipped = 0;
|
||||
let skipped_reason_counts = {};
|
||||
let prepared = [];
|
||||
let tag_map = {};
|
||||
|
||||
for (let i = 0; i < length(outbounds); i++) {
|
||||
let outbound = outbounds[i];
|
||||
@@ -568,6 +612,8 @@ function prepare_subscription(config_path, outbounds_path, output_path, supports
|
||||
let tag = unique_tag(base_tag, taken);
|
||||
let outbound_copy = copy_outbound(outbound);
|
||||
outbound_copy.tag = tag;
|
||||
let is_hidden = outbound_is_hidden(outbound);
|
||||
tag_map[base_tag] = tag;
|
||||
|
||||
push(prepared, outbound_copy);
|
||||
push(tags, tag);
|
||||
@@ -575,9 +621,12 @@ function prepare_subscription(config_path, outbounds_path, output_path, supports
|
||||
push(servers, outbound.server || "");
|
||||
push(links, outbound.share_link || "");
|
||||
push(source_indices, i + 1);
|
||||
push(visible, !is_hidden);
|
||||
taken[tag] = true;
|
||||
}
|
||||
|
||||
rewrite_prepared_outbound_references(prepared, tag_map);
|
||||
|
||||
if (!write_file_json(output_path, {
|
||||
outbounds: prepared,
|
||||
links,
|
||||
@@ -586,7 +635,8 @@ function prepare_subscription(config_path, outbounds_path, output_path, supports
|
||||
servers,
|
||||
skipped,
|
||||
skipped_reason_counts: length(keys(skipped_reason_counts)) > 0 ? skipped_reason_counts : [],
|
||||
tags
|
||||
tags,
|
||||
visible
|
||||
}))
|
||||
exit(1);
|
||||
}
|
||||
@@ -691,15 +741,36 @@ function prepare_validation(new_outbounds_path, updated_path, validation_path) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
function prepared_entry_visible(prepared, index) {
|
||||
let visible = array_or_empty(prepared.visible);
|
||||
return index >= length(visible) || visible[index] !== false;
|
||||
}
|
||||
|
||||
function prepared_visible_tags(prepared) {
|
||||
let tags = array_or_empty(prepared.tags);
|
||||
let result = [];
|
||||
for (let i = 0; i < length(tags); i++) {
|
||||
if (prepared_entry_visible(prepared, i))
|
||||
push(result, tags[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function prepared_link_refs(prepared, source_section) {
|
||||
let tags = array_or_empty(prepared.tags);
|
||||
let source_indices = array_or_empty(prepared.source_indices);
|
||||
let outbounds = array_or_empty(prepared.outbounds);
|
||||
let result = {};
|
||||
|
||||
if (source_section == "")
|
||||
return result;
|
||||
|
||||
for (let i = 0; i < length(tags); i++) {
|
||||
if (!prepared_entry_visible(prepared, i))
|
||||
continue;
|
||||
let outbound = type(outbounds[i]) == "object" ? outbounds[i] : {};
|
||||
if (outbound.type == "selector" || outbound.type == "urltest")
|
||||
continue;
|
||||
result[tags[i]] = {
|
||||
sourceSection: source_section,
|
||||
sourceIndex: int(source_indices[i] || (i + 1))
|
||||
@@ -712,8 +783,11 @@ function prepared_names(prepared) {
|
||||
let tags = array_or_empty(prepared.tags);
|
||||
let names = array_or_empty(prepared.names);
|
||||
let result = {};
|
||||
for (let i = 0; i < length(tags); i++)
|
||||
for (let i = 0; i < length(tags); i++) {
|
||||
if (!prepared_entry_visible(prepared, i))
|
||||
continue;
|
||||
result[tags[i]] = as_string(names[i] || tags[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -722,6 +796,8 @@ function prepared_servers(prepared) {
|
||||
let servers = array_or_empty(prepared.servers);
|
||||
let result = {};
|
||||
for (let i = 0; i < length(tags); i++) {
|
||||
if (!prepared_entry_visible(prepared, i))
|
||||
continue;
|
||||
let server = as_string(servers[i]);
|
||||
if (server != "")
|
||||
result[tags[i]] = server;
|
||||
@@ -731,8 +807,11 @@ function prepared_servers(prepared) {
|
||||
|
||||
function prepared_names_text(prepared) {
|
||||
let lines = [];
|
||||
for (let name in array_or_empty(prepared.names))
|
||||
push(lines, as_string(name));
|
||||
let names = array_or_empty(prepared.names);
|
||||
for (let i = 0; i < length(names); i++) {
|
||||
if (prepared_entry_visible(prepared, i))
|
||||
push(lines, as_string(names[i]));
|
||||
}
|
||||
return length(lines) > 0 ? join("\n", lines) + "\n" : "";
|
||||
}
|
||||
|
||||
@@ -764,6 +843,7 @@ function prepared_slice(start, end) {
|
||||
prepared.servers = slice(array_or_empty(prepared.servers), start, end);
|
||||
prepared.links = slice(array_or_empty(prepared.links), start, end);
|
||||
prepared.source_indices = slice(array_or_empty(prepared.source_indices), start, end);
|
||||
prepared.visible = slice(array_or_empty(prepared.visible), start, end);
|
||||
prepared.skipped = 0;
|
||||
prepared.skipped_reason_counts = {};
|
||||
write_json(prepared);
|
||||
@@ -771,14 +851,14 @@ function prepared_slice(start, end) {
|
||||
|
||||
function field_json(field) {
|
||||
let value = object_or_empty(read_stdin_json())[field];
|
||||
if (field == "outbounds" || field == "tags" || field == "names" || field == "servers" || field == "links" || field == "source_indices")
|
||||
if (field == "outbounds" || field == "tags" || field == "names" || field == "servers" || field == "links" || field == "source_indices" || field == "visible")
|
||||
value = array_or_empty(value);
|
||||
write_json(value == null ? [] : value);
|
||||
}
|
||||
|
||||
function prepared_field_to_file(field, output_path, count_path) {
|
||||
let value = object_or_empty(read_stdin_json())[field];
|
||||
if (field == "outbounds" || field == "tags" || field == "names" || field == "servers" || field == "links" || field == "source_indices")
|
||||
if (field == "outbounds" || field == "tags" || field == "names" || field == "servers" || field == "links" || field == "source_indices" || field == "visible")
|
||||
value = array_or_empty(value);
|
||||
if (value == null)
|
||||
value = [];
|
||||
@@ -798,6 +878,11 @@ function field_length(field) {
|
||||
print(length(value), "\n");
|
||||
}
|
||||
|
||||
function visible_length() {
|
||||
let prepared = object_or_empty(read_stdin_json());
|
||||
print(length(prepared_visible_tags(prepared)), "\n");
|
||||
}
|
||||
|
||||
function stdin_collection_length() {
|
||||
let value = read_stdin_json();
|
||||
if (type(value) != "array" && type(value) != "object")
|
||||
@@ -815,7 +900,7 @@ function print_string_array_csv(values) {
|
||||
|
||||
function tags_csv() {
|
||||
let prepared = object_or_empty(read_stdin_json());
|
||||
print_string_array_csv(array_or_empty(prepared.tags));
|
||||
print_string_array_csv(prepared_visible_tags(prepared));
|
||||
}
|
||||
|
||||
function stdin_string_array_csv() {
|
||||
@@ -824,7 +909,7 @@ function stdin_string_array_csv() {
|
||||
|
||||
function prepared_state_to_files(source_section, tags_path, tags_csv_path, names_lines_path, link_refs_path, names_path, servers_path) {
|
||||
let prepared = object_or_empty(read_stdin_json());
|
||||
let tags = array_or_empty(prepared.tags);
|
||||
let tags = prepared_visible_tags(prepared);
|
||||
let tag_values = [];
|
||||
for (let tag in tags)
|
||||
push(tag_values, as_string(tag));
|
||||
@@ -841,7 +926,7 @@ function prepared_state_to_files(source_section, tags_path, tags_csv_path, names
|
||||
function append_prepared_state_to_files(source_section, tags_path, names_lines_path, link_refs_path, names_path, servers_path) {
|
||||
let prepared = object_or_empty(read_stdin_json());
|
||||
let tags = array_or_empty(read_json_file(tags_path));
|
||||
for (let tag in array_or_empty(prepared.tags))
|
||||
for (let tag in prepared_visible_tags(prepared))
|
||||
push(tags, tag);
|
||||
|
||||
let names_lines = trim_trailing_newlines(fs.readfile(names_lines_path));
|
||||
@@ -861,9 +946,18 @@ function display_name() {
|
||||
let prepared = object_or_empty(read_stdin_json());
|
||||
let names = array_or_empty(prepared.names);
|
||||
let outbounds = array_or_empty(prepared.outbounds);
|
||||
let result = as_string(names[0]);
|
||||
if (result == "" && length(outbounds) > 0 && type(outbounds[0]) == "object")
|
||||
result = as_string(outbounds[0].tag);
|
||||
let result = "";
|
||||
let first_visible = -1;
|
||||
for (let i = 0; i < length(outbounds); i++) {
|
||||
if (prepared_entry_visible(prepared, i)) {
|
||||
first_visible = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (first_visible >= 0)
|
||||
result = as_string(names[first_visible]);
|
||||
if (result == "" && first_visible >= 0 && type(outbounds[first_visible]) == "object")
|
||||
result = as_string(outbounds[first_visible].tag);
|
||||
if (result == "")
|
||||
result = "unknown";
|
||||
result = replace(result, /[\r\n\t]/g, " ");
|
||||
@@ -904,6 +998,8 @@ else if (mode == "prepared-field-to-file")
|
||||
prepared_field_to_file(ARGV[1], ARGV[2], ARGV[3]);
|
||||
else if (mode == "prepared-length")
|
||||
field_length(ARGV[1]);
|
||||
else if (mode == "prepared-visible-count")
|
||||
visible_length();
|
||||
else if (mode == "prepared-tags-csv")
|
||||
tags_csv();
|
||||
else if (mode == "stdin-collection-length")
|
||||
|
||||
@@ -2151,6 +2151,11 @@ function xray_display_name(original_tag, tag_counts, config_index) {
|
||||
return original_tag;
|
||||
}
|
||||
|
||||
function xray_config_display_name(config, fallback) {
|
||||
let name = xray_first_string([config.remarks, config.remark, config.name, config.ps]);
|
||||
return name != "" ? name : fallback;
|
||||
}
|
||||
|
||||
function xray_source_tag(outbound, fallback) {
|
||||
let tag = as_string(outbound.tag || "");
|
||||
return tag != "" ? tag : fallback;
|
||||
@@ -2298,6 +2303,89 @@ function xray_outbound_detour(outbound) {
|
||||
return as_string(sockopt.dialerProxy || "");
|
||||
}
|
||||
|
||||
function xray_outbound_by_source_tag(source_outbounds, tag) {
|
||||
tag = as_string(tag);
|
||||
if (tag == "")
|
||||
return null;
|
||||
|
||||
for (let outbound in source_outbounds) {
|
||||
if (type(outbound) == "object" && xray_source_tag(outbound, "") == tag)
|
||||
return outbound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function xray_supported_source_tags(source_outbounds) {
|
||||
let result = {};
|
||||
for (let i = 0; i < length(source_outbounds); i++) {
|
||||
let outbound = source_outbounds[i];
|
||||
if (type(outbound) != "object" || !xray_protocol_supported(outbound.protocol))
|
||||
continue;
|
||||
|
||||
let tag = xray_source_tag(outbound, lc(as_string(outbound.protocol || "server")) + "-" + (i + 1));
|
||||
result[tag] = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function xray_primary_source_tag(config, source_outbounds) {
|
||||
let supported_tags = xray_supported_source_tags(source_outbounds);
|
||||
|
||||
for (let rule in array_or_empty(object_or_empty(config.routing).rules)) {
|
||||
let outbound_tag = as_string(object_or_empty(rule).outboundTag || "");
|
||||
if (supported_tags[outbound_tag])
|
||||
return outbound_tag;
|
||||
}
|
||||
|
||||
if (supported_tags["proxy"])
|
||||
return "proxy";
|
||||
|
||||
for (let i = 0; i < length(source_outbounds); i++) {
|
||||
let outbound = source_outbounds[i];
|
||||
if (type(outbound) != "object" || !xray_protocol_supported(outbound.protocol))
|
||||
continue;
|
||||
|
||||
let tag = xray_source_tag(outbound, lc(as_string(outbound.protocol || "server")) + "-" + (i + 1));
|
||||
if (xray_outbound_detour(outbound) == "")
|
||||
return tag;
|
||||
}
|
||||
|
||||
for (let tag in keys(supported_tags))
|
||||
return tag;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function xray_balancer_selector_matches(selector, tag) {
|
||||
selector = as_string(selector);
|
||||
tag = as_string(tag);
|
||||
if (selector == "" || tag == "")
|
||||
return false;
|
||||
return tag == selector || starts_with(tag, selector + "-") || starts_with(tag, selector);
|
||||
}
|
||||
|
||||
function xray_balancer_source_tags(config, source_outbounds) {
|
||||
let supported_tags = xray_supported_source_tags(source_outbounds);
|
||||
let selected = {};
|
||||
let result = [];
|
||||
|
||||
for (let balancer in array_or_empty(object_or_empty(config.routing).balancers)) {
|
||||
let selectors = array_or_empty(object_or_empty(balancer).selector);
|
||||
for (let tag in keys(supported_tags)) {
|
||||
for (let selector in selectors) {
|
||||
if (xray_balancer_selector_matches(selector, tag) && !selected[tag]) {
|
||||
selected[tag] = true;
|
||||
push(result, tag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function xray_tag_counts(configs) {
|
||||
let counts = {};
|
||||
for (let config in configs) {
|
||||
@@ -2312,7 +2400,7 @@ function xray_tag_counts(configs) {
|
||||
return counts;
|
||||
}
|
||||
|
||||
function xray_config_outbounds(config, config_index, config_count, tag_counts, taken) {
|
||||
function xray_plan_config_outbounds(config, config_index, config_count, tag_counts, taken) {
|
||||
let source_outbounds = array_or_empty(config.outbounds);
|
||||
let planned = [];
|
||||
let tag_map = {};
|
||||
@@ -2329,21 +2417,107 @@ function xray_config_outbounds(config, config_index, config_count, tag_counts, t
|
||||
push(planned, { outbound, original_tag, tag });
|
||||
}
|
||||
|
||||
let result = [];
|
||||
return { planned, tag_map };
|
||||
}
|
||||
|
||||
function xray_retag_planned_outbound(planned, tag_map, source_tag, new_base, config_index, config_count, taken) {
|
||||
source_tag = as_string(source_tag);
|
||||
new_base = as_string(new_base);
|
||||
if (source_tag == "" || new_base == "")
|
||||
return;
|
||||
|
||||
for (let item in planned) {
|
||||
let converted = convert_xray_outbound(item.outbound, item.tag);
|
||||
if (!converted)
|
||||
if (item.original_tag != source_tag)
|
||||
continue;
|
||||
|
||||
let display_name = xray_display_name(item.original_tag, tag_counts, config_index);
|
||||
if (display_name != "")
|
||||
converted.remark = display_name;
|
||||
let old_tag = as_string(item.tag || "");
|
||||
let new_tag = xray_unique_tag(new_base, taken);
|
||||
if (new_tag == old_tag)
|
||||
return;
|
||||
|
||||
if (old_tag != "")
|
||||
delete taken[old_tag];
|
||||
taken[new_tag] = true;
|
||||
item.tag = new_tag;
|
||||
tag_map[source_tag] = new_tag;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function xray_add_converted_outbound(result, item, tag_map, visible, display_name) {
|
||||
let converted = convert_xray_outbound(item.outbound, item.tag);
|
||||
if (!converted)
|
||||
return;
|
||||
|
||||
if (visible && display_name != "")
|
||||
converted.remark = display_name;
|
||||
if (!visible)
|
||||
converted.__podkop_hidden = true;
|
||||
|
||||
let detour = xray_outbound_detour(item.outbound);
|
||||
if (detour != "" && tag_map[detour])
|
||||
converted.detour = tag_map[detour];
|
||||
|
||||
push(result, converted);
|
||||
}
|
||||
|
||||
function xray_config_outbounds(config, config_index, config_count, tag_counts, taken) {
|
||||
let source_outbounds = array_or_empty(config.outbounds);
|
||||
let plan = xray_plan_config_outbounds(config, config_index, config_count, tag_counts, taken);
|
||||
let planned = array_or_empty(plan.planned);
|
||||
let tag_map = object_or_empty(plan.tag_map);
|
||||
let display_name = xray_config_display_name(config, "");
|
||||
let balancer_tags = xray_balancer_source_tags(config, source_outbounds);
|
||||
let visible_source_tags = {};
|
||||
let dependency_tags = {};
|
||||
let result = [];
|
||||
|
||||
if (length(balancer_tags) > 0) {
|
||||
let urltest_outbounds = [];
|
||||
for (let source_tag in balancer_tags) {
|
||||
if (tag_map[source_tag]) {
|
||||
visible_source_tags[source_tag] = false;
|
||||
push(urltest_outbounds, tag_map[source_tag]);
|
||||
}
|
||||
}
|
||||
|
||||
if (length(urltest_outbounds) > 0) {
|
||||
let group_tag = xray_unique_tag(
|
||||
display_name != "" ? display_name : xray_tag_base("urltest", config_index, config_count),
|
||||
taken
|
||||
);
|
||||
taken[group_tag] = true;
|
||||
let group = {
|
||||
type: "urltest",
|
||||
tag: group_tag,
|
||||
outbounds: urltest_outbounds,
|
||||
url: "https://www.gstatic.com/generate_204",
|
||||
interval: "10m",
|
||||
tolerance: 50,
|
||||
remark: display_name != "" ? display_name : group_tag,
|
||||
__podkop_allow_group: true
|
||||
};
|
||||
push(result, group);
|
||||
}
|
||||
} else {
|
||||
let primary_tag = xray_primary_source_tag(config, source_outbounds);
|
||||
if (primary_tag != "") {
|
||||
xray_retag_planned_outbound(planned, tag_map, primary_tag, display_name, config_index, config_count, taken);
|
||||
visible_source_tags[primary_tag] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (let item in planned) {
|
||||
let detour = xray_outbound_detour(item.outbound);
|
||||
if (detour != "" && tag_map[detour])
|
||||
converted.detour = tag_map[detour];
|
||||
dependency_tags[detour] = true;
|
||||
}
|
||||
|
||||
push(result, converted);
|
||||
for (let item in planned) {
|
||||
let visible = visible_source_tags[item.original_tag] === true;
|
||||
let hidden = !visible;
|
||||
if (visible || dependency_tags[item.original_tag] || visible_source_tags[item.original_tag] === false)
|
||||
xray_add_converted_outbound(result, item, tag_map, !hidden, display_name != "" ? display_name : xray_display_name(item.original_tag, tag_counts, config_index));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user