这个脚本用于解决ssr-win更新pac为gfwlist出错问题.
必要的修改
用记事本打开update-pac-from-gfwlist.ps1,
修改第一行的 “C:\bin\ssr-win”, 改成你的ShadowsocksR程序的文件夹路径.
运行脚本
在update-pac-from-gfwlist.ps1脚本的文件夹,
按住shift键, 再按鼠标右键, 弹出菜单, 点击”在此处打开PowerShell窗口”
输入.\update-pac-from-gfwlist.ps1, 按enter键执行脚本.
还可以设置任务计划, 让脚本每周自动运行一次.
使用自定义规则
打开ShadowsocksR程序文件夹下的user-rule.txt
每行添加一个规则:
比如
||w3schools.com^
||jetbrains.com^
||ubuntu.com^
然后按照上面的方法再次运行脚本.
这样你就可以打开w3schools.com了.
自定义规则语法简要说明:
w3schools.com这个网站打不开, 你就在user-rule.txt添加一行||w3schools.com^
前面加上||, 后面加上^
自定义规则语法详细说明:
http://honglu.me/2015/06/26/ShadowSocks%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A7%84%E5%88%99/
可能遇到的错误:
Invoke-webrequest : 无法连接到远程服务器
所在位置 C:\Users\jin7\Desktop\update-pac-from-gfwlist.ps1:2 字符: 13
+ $gfwlist = (Invoke-webrequest -URI $uri -Proxy “http://127.0.0.1:1080 …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
请打开shadowsocksR翻墙软件重试.
如果还不行, 请删掉update-pac-from-gfwlist.ps1文件第二行的 -Proxy “http://127.0.0.1:1080”
本脚本只在Windows10 x64环境下做过测试.
$ssrPath = "C:\bin\ssr-win" # 把ShadowsocksR程序的目录路径改成你的 $uri = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt" $gfwlist = (Invoke-webrequest -URI $uri -Proxy "http://127.0.0.1:1080").content $pac = $gfwlist -replace "`r`n", '' $pac = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($pac)) $userRule = Get-Content "$ssrPath\user-rule.txt" -raw -Encoding UTF8 $pac += $userRule $pac = $pac -replace [regex]::Escape('[AutoProxy 0.2.9]'), '' $pacArr = @() $pacArr = $pac.Split("`r`n") $pacArr = $pacArr | ForEach-Object { $_ -replace "^!.*$", '' } | Where-Object {$_.trim() -ne ""} | Select-Object -unique | ConvertTo-Json $pacJs = 'var rules = ' + $pacArr + ';' $headerJs = @' var direct = "__DIRECT__"; if (direct == "__DIR" + "ECT__") direct = "DIRECT;"; var wall_proxy = function(){ return "__PROXY__"; }; var wall_v6_proxy = function(){ return "__PROXY__"; }; var nowall_proxy = function(){ return direct; }; var ip_proxy = function(){ return nowall_proxy(); }; var ipv6_proxy = function(){ return nowall_proxy(); }; '@ $footerJs = @' function createDict() { var result = {}; result.__proto__ = null; return result; } function getOwnPropertyDescriptor(obj, key) { if (obj.hasOwnProperty(key)) { return obj[key]; } return null; } function extend(subclass, superclass, definition) { if (Object.__proto__) { definition.__proto__ = superclass.prototype; subclass.prototype = definition; } else { var tmpclass = function(){}, ret; tmpclass.prototype = superclass.prototype; subclass.prototype = new tmpclass(); subclass.prototype.constructor = superclass; for (var i in definition) { if (definition.hasOwnProperty(i)) { subclass.prototype[i] = definition[i]; } } } } function Filter(text) { this.text = text; this.subscriptions = []; } Filter.prototype = { text: null, subscriptions: null, toString: function() { return this.text; } }; Filter.knownFilters = createDict(); Filter.elemhideRegExp = /^([^\/\*\|\@"!]*?)#(\@)?(?:([\w\-]+|\*)((?:\([\w\-]+(?:[$^*]?=[^\(\)"]*)?\))*)|#([^{}]+))$/; Filter.regexpRegExp = /^(@@)?\/.*\/(?:\$~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)?$/; Filter.optionsRegExp = /\$(~?[\w\-]+(?:=[^,\s]+)?(?:,~?[\w\-]+(?:=[^,\s]+)?)*)$/; Filter.fromText = function(text) { if (text in Filter.knownFilters) { return Filter.knownFilters[text]; } var ret; if (text.charAt(0) == "!") { ret = new CommentFilter(text); } else { ret = RegExpFilter.fromText(text); } Filter.knownFilters[ret.text] = ret; return ret; }; function InvalidFilter(text, reason) { Filter.call(this, text); this.reason = reason; } extend(InvalidFilter, Filter, { reason: null }); function CommentFilter(text) { Filter.call(this, text); } extend(CommentFilter, Filter, { }); function ActiveFilter(text, domains) { Filter.call(this, text); this.domainSource = domains; } extend(ActiveFilter, Filter, { domainSource: null, domainSeparator: null, ignoreTrailingDot: true, domainSourceIsUpperCase: false, getDomains: function() { var prop = getOwnPropertyDescriptor(this, "domains"); if (prop) { return prop; } var domains = null; if (this.domainSource) { var source = this.domainSource; if (!this.domainSourceIsUpperCase) { source = source.toUpperCase(); } var list = source.split(this.domainSeparator); if (list.length == 1 && (list[0]).charAt(0) != "~") { domains = createDict(); domains[""] = false; if (this.ignoreTrailingDot) { list[0] = list[0].replace(/\.+$/, ""); } domains[list[0]] = true; } else { var hasIncludes = false; for (var i = 0; i < list.length; i++) { var domain = list[i]; if (this.ignoreTrailingDot) { domain = domain.replace(/\.+$/, ""); } if (domain == "") { continue; } var include; if (domain.charAt(0) == "~") { include = false; domain = domain.substr(1); } else { include = true; hasIncludes = true; } if (!domains) { domains = createDict(); } domains[domain] = include; } domains[""] = !hasIncludes; } this.domainSource = null; } return this.domains; }, sitekeys: null, isActiveOnDomain: function(docDomain, sitekey) { if (this.getSitekeys() && (!sitekey || this.getSitekeys().indexOf(sitekey.toUpperCase()) < 0)) { return false; } if (!this.getDomains()) { return true; } if (!docDomain) { return this.getDomains()[""]; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); while (true) { if (docDomain in this.getDomains()) { return this.domains[docDomain]; } var nextDot = docDomain.indexOf("."); if (nextDot < 0) { break; } docDomain = docDomain.substr(nextDot + 1); } return this.domains[""]; }, isActiveOnlyOnDomain: function(docDomain) { if (!docDomain || !this.getDomains() || this.getDomains()[""]) { return false; } if (this.ignoreTrailingDot) { docDomain = docDomain.replace(/\.+$/, ""); } docDomain = docDomain.toUpperCase(); for (var domain in this.getDomains()) { if (this.domains[domain] && domain != docDomain && (domain.length = 2 && regexpSource.charAt(0) == "/" && regexpSource.charAt(regexpSource.length - 1) == "/") { var regexp = new RegExp(regexpSource.substr(1, regexpSource.length - 2), this.matchCase ? "" : "i"); this.regexp = regexp; } else { this.regexpSource = regexpSource; } } extend(RegExpFilter, ActiveFilter, { domainSourceIsUpperCase: true, length: 1, domainSeparator: "|", regexpSource: null, getRegexp: function() { var prop = getOwnPropertyDescriptor(this, "regexp"); if (prop) { return prop; } var source = this.regexpSource.replace(/\*+/g, "*").replace(/\^\|$/, "^").replace(/\W/g, "\\$&").replace(/\\\*/g, ".*").replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)").replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?").replace(/^\\\|/, "^").replace(/\\\|$/, "$").replace(/^(\.\*)/, "").replace(/(\.\*)$/, ""); var regexp = new RegExp(source, this.matchCase ? "" : "i"); this.regexp = regexp; return regexp; }, pacType: 2147483647, matchCase: false, thirdParty: null, sitekeySource: null, getSitekeys: function() { var prop = getOwnPropertyDescriptor(this, "sitekeys"); if (prop) { return prop; } var sitekeys = null; if (this.sitekeySource) { sitekeys = this.sitekeySource.split("|"); this.sitekeySource = null; } this.sitekeys = sitekeys; return this.sitekeys; }, matches: function(location, pacType, docDomain, thirdParty, sitekey) { if (this.getRegexp().test(location) && this.isActiveOnDomain(docDomain, sitekey)) { return true; } return false; } }); RegExpFilter.prototype["0"] = "#this"; RegExpFilter.fromText = function(text) { var blocking = true; var origText = text; if (text.indexOf("@@") == 0) { blocking = false; text = text.substr(2); } var pacType = null; var matchCase = null; var domains = null; var sitekeys = null; var thirdParty = null; var collapse = null; var options; var match = text.indexOf("$") >= 0 ? Filter.optionsRegExp.exec(text) : null; if (match) { options = match[1].toUpperCase().split(","); text = match.input.substr(0, match.index); for (var _loopIndex6 = 0; _loopIndex6 = 0) { value = option.substr(separatorIndex + 1); option = option.substr(0, separatorIndex); } option = option.replace(/-/, "_"); if (option in RegExpFilter.typeMap) { if (pacType == null) { pacType = 0; } pacType |= RegExpFilter.typeMap[option]; } else if (option.charAt(0) == "~" && option.substr(1) in RegExpFilter.typeMap) { if (pacType == null) { pacType = RegExpFilter.prototype.pacType; } pacType &= ~RegExpFilter.typeMap[option.substr(1)]; } else if (option == "MATCH_CASE") { matchCase = true; } else if (option == "~MATCH_CASE") { matchCase = false; } else if (option == "DOMAIN" && typeof value != "undefined") { domains = value; } else if (option == "THIRD_PARTY") { thirdParty = true; } else if (option == "~THIRD_PARTY") { thirdParty = false; } else if (option == "COLLAPSE") { collapse = true; } else if (option == "~COLLAPSE") { collapse = false; } else if (option == "SITEKEY" && typeof value != "undefined") { sitekeys = value; } else { return new InvalidFilter(origText, "Unknown option " + option.toLowerCase()); } } } if (!blocking && (pacType == null || pacType & RegExpFilter.typeMap.DOCUMENT) && (!options || options.indexOf("DOCUMENT") < 0) && !/^\|?[\w\-]+:/.test(text)) { if (pacType == null) { pacType = RegExpFilter.prototype.pacType; } pacType &= ~RegExpFilter.typeMap.DOCUMENT; } try { if (blocking) { return new BlockingFilter(origText, text, pacType, matchCase, domains, thirdParty, sitekeys, collapse); } else { return new WhitelistFilter(origText, text, pacType, matchCase, domains, thirdParty, sitekeys); } } catch (e) { return new InvalidFilter(origText, e); } }; RegExpFilter.typeMap = { OTHER: 1, SCRIPT: 2, IMAGE: 4, STYLESHEET: 8, OBJECT: 16, SUBDOCUMENT: 32, DOCUMENT: 64, XBL: 1, PING: 1, XMLHTTPREQUEST: 2048, OBJECT_SUBREQUEST: 4096, DTD: 1, MEDIA: 16384, FONT: 32768, BACKGROUND: 4, POPUP: 268435456, ELEMHIDE: 1073741824 }; RegExpFilter.prototype.pacType &= ~ (RegExpFilter.typeMap.ELEMHIDE | RegExpFilter.typeMap.POPUP); function BlockingFilter(text, regexpSource, pacType, matchCase, domains, thirdParty, sitekeys, collapse) { RegExpFilter.call(this, text, regexpSource, pacType, matchCase, domains, thirdParty, sitekeys); this.collapse = collapse; } extend(BlockingFilter, RegExpFilter, { collapse: null }); function WhitelistFilter(text, regexpSource, pacType, matchCase, domains, thirdParty, sitekeys) { RegExpFilter.call(this, text, regexpSource, pacType, matchCase, domains, thirdParty, sitekeys); } extend(WhitelistFilter, RegExpFilter, { }); function Matcher() { this.clear(); } Matcher.prototype = { filterByKeyword: null, keywordByFilter: null, clear: function() { this.filterByKeyword = createDict(); this.keywordByFilter = createDict(); }, add: function(filter) { if (filter.text in this.keywordByFilter) { return; } var keyword = this.findKeyword(filter); var oldEntry = this.filterByKeyword[keyword]; if (typeof oldEntry == "undefined") { this.filterByKeyword[keyword] = filter; } else if (oldEntry.length == 1) { this.filterByKeyword[keyword] = [oldEntry, filter]; } else { oldEntry.push(filter); } this.keywordByFilter[filter.text] = keyword; }, remove: function(filter) { if (!(filter.text in this.keywordByFilter)) { return; } var keyword = this.keywordByFilter[filter.text]; var list = this.filterByKeyword[keyword]; if (list.length = 0) { list.splice(index, 1); if (list.length == 1) { this.filterByKeyword[keyword] = list[0]; } } } delete this.keywordByFilter[filter.text]; }, findKeyword: function(filter) { var result = ""; var text = filter.text; if (Filter.regexpRegExp.test(text)) { return result; } var match = Filter.optionsRegExp.exec(text); if (match) { text = match.input.substr(0, match.index); } if (text.substr(0, 2) == "@@") { text = text.substr(2); } var candidates = text.toLowerCase().match(/[^a-z0-9%*][a-z0-9%]{3,}(?=[^a-z0-9%*])/g); if (!candidates) { return result; } var hash = this.filterByKeyword; var resultCount = 16777215; var resultLength = 0; for (var i = 0, l = candidates.length; i < l; i++) { var candidate = candidates[i].substr(1); var count = candidate in hash ? hash[candidate].length : 0; if (count resultLength) { result = candidate; resultCount = count; resultLength = candidate.length; } } return result; }, hasFilter: function(filter) { return filter.text in this.keywordByFilter; }, getKeywordForFilter: function(filter) { if (filter.text in this.keywordByFilter) { return this.keywordByFilter[filter.text]; } else { return null; } }, _checkEntryMatch: function(keyword, location, pacType, docDomain, thirdParty, sitekey) { var list = this.filterByKeyword[keyword]; for (var i = 0; i < list.length; i++) { var filter = list[i]; if (filter == "#this") { filter = list; } if (filter.matches(location, pacType, docDomain, thirdParty, sitekey)) { return filter; } } return null; }, matchesAny: function(location, pacType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); for (var i = 0, l = candidates.length; i 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, remove: function(filter) { if (filter instanceof WhitelistFilter) { this.whitelist.remove(filter); } else { this.blacklist.remove(filter); } if (this.cacheEntries > 0) { this.resultCache = createDict(); this.cacheEntries = 0; } }, findKeyword: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.findKeyword(filter); } else { return this.blacklist.findKeyword(filter); } }, hasFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.hasFilter(filter); } else { return this.blacklist.hasFilter(filter); } }, getKeywordForFilter: function(filter) { if (filter instanceof WhitelistFilter) { return this.whitelist.getKeywordForFilter(filter); } else { return this.blacklist.getKeywordForFilter(filter); } }, isSlowFilter: function(filter) { var matcher = filter instanceof WhitelistFilter ? this.whitelist : this.blacklist; if (matcher.hasFilter(filter)) { return !matcher.getKeywordForFilter(filter); } else { return !matcher.findKeyword(filter); } }, matchesAnyInternal: function(location, pacType, docDomain, thirdParty, sitekey) { var candidates = location.toLowerCase().match(/[a-z0-9%]{3,}/g); if (candidates === null) { candidates = []; } candidates.push(""); var blacklistHit = null; for (var i = 0, l = candidates.length; i = CombinedMatcher.maxCacheEntries) { this.resultCache = createDict(); this.cacheEntries = 0; } this.resultCache[key] = result; this.cacheEntries++; return result; } }; var defaultMatcher = new CombinedMatcher(); for (var i = 0; i < rules.length; i++) { defaultMatcher.add(Filter.fromText(rules[i])); } var subnetIpRangeList = [ 0,1, 167772160,184549376, //10.0.0.0/8 2886729728,2887778304, //172.16.0.0/12 3232235520,3232301056, //192.168.0.0/16 2130706432,2130706688 //127.0.0.0/24 ]; function convertAddress(ipchars) { var bytes = ipchars.split('.'); var result = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] <>> 0; } function check_ipv4(host) { var re_ipv4 = /^\d+\.\d+\.\d+\.\d+$/g; if (re_ipv4.test(host)) { return true; } } function check_ipv6(host) { var re_ipv6 = /^\[?([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}\]?$/g; if (re_ipv6.test(host)) { return true; } } function check_ipv6_dns(dnsstr) { var re_ipv6 = /([a-fA-F0-9]{0,4}\:){1,7}[a-fA-F0-9]{0,4}(%[0-9]+)?/g; if (re_ipv6.test(dnsstr)) { return true; } } function isInSubnetRange(ipRange, intIp) { for ( var i = 0; i < 10; i += 2 ) { if ( ipRange[i] <= intIp && intIp < ipRange[i+1] ) return true; } } function getProxyFromIP(strIp) { var intIp = convertAddress(strIp); if ( isInSubnetRange(subnetIpRangeList, intIp) ) { return direct; } return ip_proxy(); } function FindProxyForURL(url, host) { if ( isPlainHostName(host) === true ) { return direct; } if (defaultMatcher.matchesAny(url, host) instanceof BlockingFilter) { return wall_proxy(); } if ( check_ipv4(host) === true ) { return getProxyFromIP(host); } return direct; } '@ "$headerJs`r`n`r`n$pacJs`r`n`r`n$footerJs" | Out-File "$ssrPath\pac.txt" -Encoding utf8 -NoNewline