Skip to content

Instantly share code, notes, and snippets.

@ZeppLu
Created May 3, 2019 17:50
Show Gist options
  • Save ZeppLu/9c955d56799a7081f09bad0968a14956 to your computer and use it in GitHub Desktop.
Save ZeppLu/9c955d56799a7081f09bad0968a14956 to your computer and use it in GitHub Desktop.
Convert the famous https://github.com/h2y/Shadowrocket-ADBlock-Rules to V2Ray routing rules, in JSON format.
#!/usr/bin/env python3
import json
import requests
# usage: ./h2y_to_v2ray.py > rules.json
# then open rules.json, there's a list of RuleObjects, copy N' paste, enjoy!
SR_CONF_URL = "https://raw.githubusercontent.com/h2y/Shadowrocket-ADBlock-Rules/master/sr_top500_banlist_ad.conf"
PROXY_TAG = "proxy"
BLOCK_TAG = "block"
INDENT = 2
INIT_LEVEL = 2
def parse(sr_conf):
"""
a simple shadowrocket config file parser, which returns [Rule] section only
"""
# all states: "before rule", "in rule", "after rule"
# I'm too lazy to use an enum
state = "before rule"
next_state = "before rule"
# I'm too lazy to use a dataframe, too
sr_rules = {
"DOMAIN-SUFFIX": { "Reject": [], "Proxy" : [], },
"DOMAIN-KEYWORD": { "Reject": [], "Proxy" : [], },
"IP-CIDR": { "Reject": [], "Proxy" : [], }
}
for line in sr_conf.split('\n'):
if state == "before rule":
if line == "[Rule]":
next_state = "in rule"
elif state == "in rule":
if line.startswith(('#', 'FINAL')): # ignore comment and default rule
pass
elif not line: # ignore empty line
pass
elif line[0] == '[': # new section
next_state = "after rule"
else:
[match_method, target, outbound] = line.split(',')
sr_rules[match_method][outbound].append(target)
elif state == "after rule":
pass
else:
raise
state = next_state
return sr_rules
def convert(sr_rules):
"""
convert shadowrocket rules to v2ray rules
"""
process = lambda domain_suffix: "domain:" + domain_suffix.strip('.')
v2_rules = [
{
"domain": (sr_rules['DOMAIN-KEYWORD']['Reject'] +
[process(d) for d in sr_rules['DOMAIN-SUFFIX']['Reject']]),
"outboundTag": BLOCK_TAG,
"type": "field"
},
{
"domain": (sr_rules['DOMAIN-KEYWORD']['Proxy'] +
[process(d) for d in sr_rules['DOMAIN-SUFFIX']['Proxy']]),
"outboundTag": PROXY_TAG,
"type": "field"
},
{
"ip": sr_rules['IP-CIDR']['Reject'],
"outboundTag": BLOCK_TAG,
"type": "field"
},
{
"ip": sr_rules['IP-CIDR']['Proxy'],
"outboundTag": PROXY_TAG,
"type": "field"
},
]
return v2_rules
def main():
r = requests.get(SR_CONF_URL)
if r.status_code != 200:
raise
sr_conf = r.text
sr_rules = parse(sr_conf)
v2_rules = convert(sr_rules)
rule_objects = json.dumps(v2_rules, indent=INDENT)
for line in rule_objects.split('\n'):
print(" "*(INDENT*INIT_LEVEL) + line)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment