mirror of
https://github.com/MetaCubeX/subconverter.git
synced 2025-09-26 23:09:20 +08:00
Enhanced Profile Configuration Parsing and Tag Matching in profile.ini (#820)
1. exclude/include supports tag matching for "!!GROUP=", "!!GROUPID=", and "!!INSERT=". 2. exclude/include supports multiple expressions separated by the delimiter '`'. 3. Supports parsing multi-line contents for "url=", "rename=", and "exclude/include=" by merging them into a single line using delimiters.
This commit is contained in:
parent
e17246df7c
commit
c2610a3804
@ -174,13 +174,13 @@ int addNodes(std::string link, std::vector<Proxy> &allNodes, int groupID, parse_
|
||||
if(!getSubInfoFromHeader(extra_headers, subInfo))
|
||||
getSubInfoFromNodes(nodes, stream_rules, time_rules, subInfo);
|
||||
}
|
||||
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
|
||||
for(Proxy &x : nodes)
|
||||
{
|
||||
x.GroupId = groupID;
|
||||
if(custom_group.size())
|
||||
x.Group = custom_group;
|
||||
}
|
||||
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
|
||||
copyNodes(nodes, allNodes);
|
||||
}
|
||||
else
|
||||
@ -206,13 +206,13 @@ int addNodes(std::string link, std::vector<Proxy> &allNodes, int groupID, parse_
|
||||
{
|
||||
getSubInfoFromNodes(nodes, stream_rules, time_rules, subInfo);
|
||||
}
|
||||
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
|
||||
for(Proxy &x : nodes)
|
||||
{
|
||||
x.GroupId = groupID;
|
||||
if(!custom_group.empty())
|
||||
x.Group = custom_group;
|
||||
}
|
||||
filterNodes(nodes, exclude_remarks, include_remarks, groupID);
|
||||
copyNodes(nodes, allNodes);
|
||||
break;
|
||||
default:
|
||||
|
@ -531,10 +531,58 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
ext.rename_array = safe_get_renames();
|
||||
|
||||
/// check custom include/exclude settings
|
||||
if(!argIncludeRemark.empty() && regValid(argIncludeRemark))
|
||||
lIncludeRemarks = string_array{argIncludeRemark};
|
||||
if(!argExcludeRemark.empty() && regValid(argExcludeRemark))
|
||||
lExcludeRemarks = string_array{argExcludeRemark};
|
||||
if (!argIncludeRemark.empty())
|
||||
{
|
||||
// Check if the delimiter ` is present
|
||||
if (argIncludeRemark.find('`') != std::string::npos)
|
||||
{
|
||||
// Split argIncludeRemark using ` as the delimiter
|
||||
string_array splitIncludeRemarks = split(argIncludeRemark, "`");
|
||||
// Filter out invalid regular expressions
|
||||
string_array tempValidRemarks;
|
||||
for (const auto& remark : splitIncludeRemarks)
|
||||
{
|
||||
if (!remark.empty() && regValid(remark)) // Validate each split element using regValid
|
||||
{
|
||||
tempValidRemarks.push_back(remark);
|
||||
}
|
||||
}
|
||||
if (!tempValidRemarks.empty())
|
||||
lIncludeRemarks = tempValidRemarks;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no delimiter is found, follow the original logic
|
||||
if (regValid(argIncludeRemark))
|
||||
lIncludeRemarks = string_array{argIncludeRemark};
|
||||
}
|
||||
}
|
||||
if (!argExcludeRemark.empty())
|
||||
{
|
||||
// Check if the delimiter ` is present
|
||||
if (argExcludeRemark.find('`') != std::string::npos)
|
||||
{
|
||||
// Split argExcludeRemark using ` as the delimiter
|
||||
string_array splitExcludeRemarks = split(argExcludeRemark, "`");
|
||||
// Filter out invalid regular expressions
|
||||
string_array tempValidRemarks;
|
||||
for (const auto& remark : splitExcludeRemarks)
|
||||
{
|
||||
if (!remark.empty() && regValid(remark)) // Validate each split element using regValid
|
||||
{
|
||||
tempValidRemarks.push_back(remark);
|
||||
}
|
||||
}
|
||||
if (!tempValidRemarks.empty())
|
||||
lExcludeRemarks = tempValidRemarks;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no delimiter is found, follow the original logic
|
||||
if (regValid(argExcludeRemark))
|
||||
lExcludeRemarks = string_array{argExcludeRemark};
|
||||
}
|
||||
}
|
||||
|
||||
/// initialize script runtime
|
||||
if(authorized && !global.scriptCleanContext)
|
||||
@ -569,6 +617,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
groupID = -1;
|
||||
urls = split(global.insertUrls, "|");
|
||||
// Remove empty urls
|
||||
urls.erase(std::remove_if(urls.begin(), urls.end(), [](const std::string& str) { return str.empty(); }), urls.end());
|
||||
importItems(urls, true);
|
||||
for(std::string &x : urls)
|
||||
{
|
||||
@ -588,6 +638,8 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS)
|
||||
}
|
||||
}
|
||||
urls = split(argUrl, "|");
|
||||
// Remove empty urls
|
||||
urls.erase(std::remove_if(urls.begin(), urls.end(), [](const std::string& str) { return str.empty(); }), urls.end());
|
||||
importItems(urls, true);
|
||||
groupID = 0;
|
||||
for(std::string &x : urls)
|
||||
@ -1154,6 +1206,34 @@ std::string surgeConfToClash(RESPONSE_CALLBACK_ARGS)
|
||||
return YAML::Dump(clash);
|
||||
}
|
||||
|
||||
// Merge multiple key-values based on delimiters
|
||||
static void merge_values(const string_multimap& source,
|
||||
const std::string& key,
|
||||
std::string& merged,
|
||||
char delimiter)
|
||||
{
|
||||
auto range = source.equal_range(key);
|
||||
for (auto iter = range.first; iter != range.second; ++iter)
|
||||
{
|
||||
if (!iter->second.empty())
|
||||
{
|
||||
if (!merged.empty()) merged += delimiter;
|
||||
merged += iter->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update container
|
||||
static void update_container(string_multimap& container,
|
||||
const std::string& key,
|
||||
const std::string& merged)
|
||||
{
|
||||
if (!merged.empty()) {
|
||||
container.erase(key);
|
||||
container.emplace(key, merged);
|
||||
}
|
||||
}
|
||||
|
||||
std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
{
|
||||
auto &argument = request.argument;
|
||||
@ -1221,14 +1301,13 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
return "Forbidden";
|
||||
}
|
||||
}
|
||||
/// check if more than one profile is provided
|
||||
|
||||
// Handle url
|
||||
std::string all_urls;
|
||||
merge_values(contents, "url", all_urls, '|');
|
||||
if(profiles.size() > 1)
|
||||
{
|
||||
writeLog(0, "Multiple profiles are provided. Trying to combine profiles...", LOG_TYPE_INFO);
|
||||
std::string all_urls, url;
|
||||
auto iter = contents.find("url");
|
||||
if(iter != contents.end())
|
||||
all_urls = iter->second;
|
||||
for(size_t i = 1; i < profiles.size(); i++)
|
||||
{
|
||||
name = profiles[i];
|
||||
@ -1242,10 +1321,12 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
writeLog(0, "Ignoring broken profile '" + name + "'...", LOG_LEVEL_WARNING);
|
||||
continue;
|
||||
}
|
||||
url = ini.get("Profile", "url");
|
||||
if(!url.empty())
|
||||
string_multimap profile_items;
|
||||
ini.get_items("Profile", profile_items); // Get all key-value pairs in the [Profile] section
|
||||
size_t before_length = all_urls.length();
|
||||
merge_values(profile_items, "url", all_urls, '|');
|
||||
if (all_urls.length() > before_length)
|
||||
{
|
||||
all_urls += "|" + url;
|
||||
writeLog(0, "Profile url from '" + name + "' added.", LOG_LEVEL_INFO);
|
||||
}
|
||||
else
|
||||
@ -1253,8 +1334,24 @@ std::string getProfile(RESPONSE_CALLBACK_ARGS)
|
||||
writeLog(0, "Profile '" + name + "' does not have url key. Skipping...", LOG_LEVEL_INFO);
|
||||
}
|
||||
}
|
||||
iter->second = all_urls;
|
||||
}
|
||||
// Update the url key-value pairs in contents uniformly
|
||||
update_container(contents, "url", all_urls);
|
||||
|
||||
// Handle rename
|
||||
std::string all_renames;
|
||||
merge_values(contents, "rename", all_renames, '`');
|
||||
update_container(contents, "rename", all_renames);
|
||||
|
||||
// Handle exclude
|
||||
std::string all_excludes;
|
||||
merge_values(contents, "exclude", all_excludes, '`');
|
||||
update_container(contents, "exclude", all_excludes);
|
||||
|
||||
// Handle include
|
||||
std::string all_includes;
|
||||
merge_values(contents, "include", all_includes, '`');
|
||||
update_container(contents, "include", all_includes);
|
||||
|
||||
contents.emplace("token", token);
|
||||
contents.emplace("profile_data", base64Encode(global.managedConfigPrefix + "/getprofile?" + joinArguments(argument)));
|
||||
|
Loading…
Reference in New Issue
Block a user