diff --git a/README-cn.md b/README-cn.md index 87d8ff4..5f81532 100644 --- a/README-cn.md +++ b/README-cn.md @@ -53,7 +53,7 @@ http://127.0.0.1:25500/sub?target=%TARGET%&url=%URL%&config=%CONFIG% | url | 必要 | https%3A%2F%2Fwww.xxx.com | 指机场所提供的订阅链接,需要经过 [URLEncode](https://www.urlencoder.org/) 处理 | | config | 可选 | https%3A%2F%2Fwww.xxx.com | 指远程 `pref.ini` (包含分组和规则部分),需要经过 [URLEncode](https://www.urlencoder.org/) 处理,可查看 [示例仓库](https://github.com/lzdnico/subconverteriniexample) 寻找灵感,默认加载本地设置文件 | -运行 `subconverter.exe` 后,按照 [调用说明](###调用说明) 的对应内容替换即可得到一份使用**神机规则**的配置文件。 +运行 subconverter 主程序后,按照 [调用说明](###调用说明) 的对应内容替换即可得到一份使用**神机规则**的配置文件。 此外,如果你需要将多个订阅合成一份, 则要在上方所提及的 URLEncode 之前使用 '|' 来分隔链接。 @@ -70,7 +70,7 @@ https://dler.cloud/subscribe/ABCDE?clash=vmess|https://rich.cloud/subscribe/ABCD 接着通过 URLEncode 后可以得到: https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess%7Chttps%3A%2F%2Frich.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess -然后将想要的 %TARGET% (即 clash)和上一步所得到的 %URL% 填入调用地址中: +然后将想要的 %TARGET% (即 clash) 和上一步所得到的 %URL% 填入调用地址中: http://127.0.0.1:25500/sub?target=clash&url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess%7Chttps%3A%2F%2Frich.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess 最后将该链接填写至 Clash 的订阅处就大功告成了。 @@ -135,7 +135,7 @@ exclude=%28%E6%B5%81%E9%87%8F%7C%E5%AE%98%E7%BD%91%29 url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess 接着将所有元素进行拼接: -http://127.0.0.1:25500/sub?surge&ver=4&tfo=true&udp=true&emoji=true&exclude=%28%E6%B5%81%E9%87%8F%7C%E5%AE%98%E7%BD%91%29&url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess +http://127.0.0.1:25500/sub?target=surge&ver=4&tfo=true&udp=true&emoji=true&exclude=%28%E6%B5%81%E9%87%8F%7C%E5%AE%98%E7%BD%91%29&url=https%3A%2F%2Fdler.cloud%2Fsubscribe%2FABCDE%3Fclash%3Dvmess 最后将该链接填写至 Surge 的订阅处就大功告成了。 ``` @@ -418,7 +418,7 @@ custom_proxy_group=🇯🇵 JP`select`沪日`日本 > 自动上传 gist ,可以用于 Clash For Android / Surge 等进行远程订阅 -在程序目录内的 [gistconf.ini](./gistconf.ini) 中添加 [Personal Access Token](https://github.com/settings/tokens/new),在链接后加上 `upload=true` 就会在更新好后自动上传 gist。 +在程序目录内的 [gistconf.ini](./base/gistconf.ini) 中添加 [Personal Access Token](https://github.com/settings/tokens/new),在链接后加上 `&upload=true` 就会在更新好后自动上传 gist。 例如: ```ini diff --git a/base/example_external_config.ini b/base/example_external_config.ini new file mode 100644 index 0000000..6439550 --- /dev/null +++ b/base/example_external_config.ini @@ -0,0 +1,35 @@ +[custom] +custom_proxy_group=Proxy`select`.*`[]AUTO`[]DIRECT`.* +custom_proxy_group=AUTO`url-test`.*`http://www.gstatic.com/generate_204`300 +custom_proxy_group=google`select`.* +custom_proxy_group=netflix`select`.* +custom_proxy_group=动画疯`select`(深台|彰化|新北|台) +custom_proxy_group=fox+`select`(HGC|HKBN|PCCW|HKT|深台|彰化|新北|台|新加坡|sg|hk|tw) +custom_proxy_group=美区影视`select`(美|美国) +custom_proxy_group=Global_media`select`.* +custom_proxy_group=Domestic`select`[]DIRECT`[]Proxy +custom_proxy_group=Apple`select`[]DIRECT`[]Proxy +custom_proxy_group=Final`select`[]Proxy`[]DIRECT +custom_proxy_group=屏蔽广告`select`[]REJECT`[]DIRECT +custom_proxy_group=UnblockNeteaseMusic`select`云音乐解锁`[]DIRECT +custom_proxy_group=Telegram`select`新加坡`[]Proxy + +enable_rule_generator=false +;surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Unbreak.list +;surge_ruleset=⛔️ 广告拦截,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Advertising.list +;surge_ruleset=🚫 运营劫持,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Hijacking.list +;surge_ruleset=🌌 YouTube,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/YouTube.list +;surge_ruleset=🎥 NETFLIX,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Netflix.list +;surge_ruleset=HBO,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/HBO.list +;surge_ruleset=Fox,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Media/Fox.list +;surge_ruleset=🌍 国外媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/GlobalMedia.list +;surge_ruleset=🌏 港台媒体,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/HKMTMedia.list +;surge_ruleset=📲 电报信息,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Telegram.list +;surge_ruleset=🔰 节点选择,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Global.list +;surge_ruleset=🍎 苹果服务,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/Apple.list +;surge_ruleset=DIRECT,https://raw.githubusercontent.com/ConnersHua/Profiles/master/Surge/Ruleset/China.list + +clash_rule_base=forcerule.yml +;surge_rule_base=surge.conf +;surfboard_rule_base=surfboard.conf +;mellow_rule_base=mellow.conf diff --git a/base/rules/LocalAreaNetwork.list b/base/rules/LocalAreaNetwork.list index a8b9e68..fd05128 100644 --- a/base/rules/LocalAreaNetwork.list +++ b/base/rules/LocalAreaNetwork.list @@ -1,10 +1,10 @@ DOMAIN-SUFFIX,local -IP-CIDR,192.168.0.0/16 -IP-CIDR,10.0.0.0/8 -IP-CIDR,172.16.0.0/12 -IP-CIDR,127.0.0.0/8 -IP-CIDR,100.64.0.0/10 -IP-CIDR6,::1/128 -IP-CIDR6,fc00::/7 -IP-CIDR6,fe80::/10 -IP-CIDR6,fd00::/8 +IP-CIDR,192.168.0.0/16,no-resolve +IP-CIDR,10.0.0.0/8,no-resolve +IP-CIDR,172.16.0.0/12,no-resolve +IP-CIDR,127.0.0.0/8,no-resolve +IP-CIDR,100.64.0.0/10,no-resolve +IP-CIDR6,::1/128,no-resolve +IP-CIDR6,fc00::/7,no-resolve +IP-CIDR6,fe80::/10,no-resolve +IP-CIDR6,fd00::/8,no-resolve diff --git a/src/ini_reader.h b/src/ini_reader.h index e15c72f..dc067b4 100644 --- a/src/ini_reader.h +++ b/src/ini_reader.h @@ -202,7 +202,7 @@ public: { last_error_index++; lineSize = strLine.size(); - if(!lineSize || strLine[0] == ';' || strLine[0] == '#') //empty lines and comments are ignored + if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored continue; if(strLine[lineSize - 1] == '\r') //remove line break { @@ -240,8 +240,11 @@ public: __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop } ini_content.emplace(curSection, itemGroup); //insert previous section to content map - read_sections.emplace_back(curSection); //add to read sections list + read_sections.push_back(curSection); //add to read sections list + if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0) + section_order.emplace_back(curSection); } + eraseElements(itemGroup); //reset section storage curSection = thisSection; //start a new section } @@ -269,6 +272,8 @@ public: } ini_content.emplace(curSection, itemGroup); //insert this section to content map read_sections.emplace_back(curSection); //add to read sections list + if(std::count(section_order.cbegin(), section_order.cend(), curSection) == 0) + section_order.emplace_back(curSection); } parsed = true; __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); //all done @@ -409,6 +414,7 @@ public: void EraseAll() { eraseElements(ini_content); + eraseElements(section_order); parsed = false; } @@ -596,6 +602,7 @@ public: string_multimap mapTemp; mapTemp.insert(std::pair(itemName, itemVal)); ini_content.insert(std::pair>(section, mapTemp)); + section_order.emplace_back(section); } __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); @@ -690,6 +697,7 @@ public: */ ini_content[newName] = std::move(ini_content[oldName]); ini_content.erase(oldName); + std::replace(section_order.begin(), section_order.end(), oldName, newName); __SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); } @@ -758,6 +766,7 @@ public: eraseElements(ini_content.at(section)); if(cached_section == section) eraseElements(cached_section_content); + //section_order.erase(std::find(section_order.begin(), section_order.end(), section)); } /** @@ -779,14 +788,17 @@ public: if(!parsed) return std::string(); - for(auto &x : ini_content) + for(auto &x : section_order) { - content += "[" + x.first + "]\n"; - for(auto &y : x.second) + content += "[" + x + "]\n"; + if(ini_content.find(x) != ini_content.end()) { - if(y.first != "{NONAME}") - content += y.first + "="; - content += y.second + "\n"; + for(auto &y : ini_content.at(x)) + { + if(y.first != "{NONAME}") + content += y.first + "="; + content += y.second + "\n"; + } } content += "\n"; } diff --git a/src/main.cpp b/src/main.cpp index 1e78502..d88c32a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -255,7 +255,19 @@ void readConf() std::cerr<<"Read preference settings completed."< rca; + extra_settings ext; + + //for external configuration + std::string ext_clash_base = clash_rule_base, ext_surge_base = surge_rule_base, ext_mellow_base = mellow_rule_base, ext_surfboard_base = surfboard_rule_base; if(!url.size()) url = default_url; @@ -347,10 +371,30 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS) if(config.size()) { std::cerr<<"External configuration file provided. Loading...\n"; + //read predefined data first extra_group = clash_extra_group; extra_ruleset = rulesets; - loadExternalConfig(config, extra_group, extra_ruleset, proxy); - refreshRulesets(extra_ruleset, rca); + //then load external configuration + ExternalConfig extconf; + loadExternalConfig(config, extconf, proxy); + if(extconf.clash_rule_base.size()) + ext_clash_base = extconf.clash_rule_base; + if(extconf.surge_rule_base.size()) + ext_surge_base = extconf.surge_rule_base; + if(extconf.surfboard_rule_base.size()) + ext_surfboard_base = extconf.surfboard_rule_base; + if(extconf.mellow_rule_base.size()) + ext_mellow_base = extconf.mellow_rule_base; + ext.enable_rule_generator = extconf.enable_rule_generator; + //load custom group + if(extconf.custom_proxy_group.size()) + extra_group = extconf.custom_proxy_group; + //load custom rules + if(extconf.overwrite_original_rules) + { + extra_ruleset = extconf.surge_ruleset; + refreshRulesets(extra_ruleset, rca); + } } else { @@ -385,7 +429,6 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS) } } - extra_settings ext; if(emoji.size()) { ext.add_emoji = ext.remove_emoji = emoji == "true"; @@ -437,12 +480,12 @@ std::string subconverter(RESPONSE_CALLBACK_ARGS) if(target == "clash" || target == "clashr") { std::cerr<<"Clash"<<((target == "clashr") ? "R" : "")<= 5) { username = trim(configs[2]); @@ -1266,6 +1268,8 @@ bool explodeSurge(std::string surge, std::string custom_port, int local_port, st { node.linkType = SPEEDTEST_MESSAGE_FOUNDHTTP; node.group = HTTP_DEFAULT_GROUP; + server = trim(configs[1]); + port = custom_port == "" ? trim(configs[2]) : custom_port; if(configs.size() >= 5) { username = trim(configs[2]); @@ -1330,7 +1334,7 @@ bool explodeSurge(std::string surge, std::string custom_port, int local_port, st node.remarks = remarks; node.server = server; - node.port = stoi(port); + node.port = to_int(port); node.id = index; nodes.push_back(node); index++; @@ -1394,7 +1398,7 @@ void explodeSSTap(std::string sstap, std::string custom_port, int local_port, st node.remarks = remarks; node.id = index; node.server = server; - node.port = stoi(port); + node.port = to_int(port); nodes.push_back(node); } } diff --git a/src/subexport.cpp b/src/subexport.cpp index 93274ef..dfcf408 100644 --- a/src/subexport.cpp +++ b/src/subexport.cpp @@ -701,7 +701,8 @@ std::string netchToClash(std::vector &nodes, std::string &base_conf, s if(ext.nodelist) return YAML::Dump(yamlnode); - rulesetToClash(yamlnode, ruleset_content_array); + if(ext.enable_rule_generator) + rulesetToClash(yamlnode, ruleset_content_array); return YAML::Dump(yamlnode); } @@ -866,6 +867,7 @@ std::string netchToSurge(std::vector &nodes, std::string &base_conf, s return output_nodelist; ini.SetCurrentSection("Proxy Group"); + ini.EraseSection(); for(std::string &x : extra_proxy_group) { eraseElements(filtered_nodelist); @@ -925,7 +927,8 @@ std::string netchToSurge(std::vector &nodes, std::string &base_conf, s ini.Set("{NONAME}", vArray[0] + " = " + proxy); //insert order } - rulesetToSurge(ini, ruleset_content_array, surge_ver); + if(ext.enable_rule_generator) + rulesetToSurge(ini, ruleset_content_array, surge_ver); return ini.ToString(); } @@ -1569,7 +1572,8 @@ void netchToMellow(std::vector &nodes, INIReader &ini, std::vector