mirror of
https://github.com/yanue/V2rayU.git
synced 2025-06-27 05:30:09 +00:00
pac file
This commit is contained in:
parent
dce29e9ec7
commit
d54375fbc8
@ -30,11 +30,11 @@
|
||||
66784B0021704E1300AD307F /* V2rayCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66784AFF21704E1300AD307F /* V2rayCore.swift */; };
|
||||
66973EB721797719001FEA1E /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66973EB621797719001FEA1E /* ServiceManagement.framework */; };
|
||||
66ACB1A021757D5B005B5881 /* MainMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66ACB19F21757D5B005B5881 /* MainMenu.swift */; };
|
||||
66BC2B87228C537F00FBB716 /* PreferencePac.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66BC2B86228C537F00FBB716 /* PreferencePac.xib */; };
|
||||
66F411B121CA49EE007AAC10 /* pac in Copy Files */ = {isa = PBXBuildFile; fileRef = 6683B1EA21C2AD1A004A1C5F /* pac */; };
|
||||
66F411B221CA49F4007AAC10 /* v2ray-core in Copy Files */ = {isa = PBXBuildFile; fileRef = 667029CF21AFB5730079EF41 /* v2ray-core */; };
|
||||
66F411B521CA8921007AAC10 /* cmd.sh in Resources */ = {isa = PBXBuildFile; fileRef = 66F411B421CA8921007AAC10 /* cmd.sh */; };
|
||||
66FEAD53217EE14C009DECF9 /* ConfigWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66FEAD4E217EE14C009DECF9 /* ConfigWindow.xib */; };
|
||||
6D6DF06E32A1DC263EDF1A8E /* PacUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF62A40417837EA751D88 /* PacUtils.swift */; };
|
||||
6D6DF16BC49BBF5F3D4B12CF /* PreferenceGeneral.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DFD8EB18FBEA30274ED0D /* PreferenceGeneral.xib */; };
|
||||
6D6DF2CF13D9FD3C7C6492A4 /* QrcodeWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF12EA09D2D80788666D0 /* QrcodeWindow.swift */; };
|
||||
6D6DF2F2DFB2234541488BBD /* PreferenceSubscript.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF5345E4582EE0EBD468D /* PreferenceSubscript.swift */; };
|
||||
@ -42,17 +42,14 @@
|
||||
6D6DF5F67A917F78FF652D45 /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DF8F5112A8407EE959998 /* .gitignore */; };
|
||||
6D6DF6553CF221AEB71913EE /* PreferenceGeneral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DFFB29020127E034AD168 /* PreferenceGeneral.swift */; };
|
||||
6D6DF6F065067CD879201FF9 /* Scanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF87840CDA04AF0E9D36E /* Scanner.swift */; };
|
||||
6D6DF75A00BCDA0C2733A718 /* PreferencePac.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DFBC0F08C2F7D573B93B7 /* PreferencePac.xib */; };
|
||||
6D6DF7C2F627A8BABECA4C32 /* tmp1.json in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DFCE2F5044A1164CB14E3 /* tmp1.json */; };
|
||||
6D6DF807BE591BE396221EF3 /* PreferenceAdvance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF701C75D8D416096D717 /* PreferenceAdvance.swift */; };
|
||||
6D6DF872C0DECC082122D783 /* tmp.json in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DF8E42F7E29CCBEFF5468 /* tmp.json */; };
|
||||
6D6DF87497313615AFE3320A /* PreferencePac.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF3151BBA6E56836AF6DE /* PreferencePac.swift */; };
|
||||
6D6DF8BFC33F97E9AFCA5A4B /* V2rayConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DFD9F5991B38B128888D6 /* V2rayConfig.swift */; };
|
||||
6D6DF93B58B654D86ACC490E /* PreferenceAbout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF870C8E334815FBA78B2 /* PreferenceAbout.swift */; };
|
||||
6D6DFB41BC9692C90A47F31B /* UserRulesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6DF587B6AF8CEE029E48BC /* UserRulesWindow.swift */; };
|
||||
6D6DFBB73E90918ED212F138 /* PreferenceAbout.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DFCD202C8F28474E9ED3C /* PreferenceAbout.xib */; };
|
||||
6D6DFD181802BAFE2933B9C9 /* PreferenceSubscript.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DFBD3C6A7344A44DDE16D /* PreferenceSubscript.xib */; };
|
||||
6D6DFD4A3A226788760150F8 /* UserRulesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6D6DF010124783F31646A895 /* UserRulesWindow.xib */; };
|
||||
F260898E336CFA5EAB07ADC9 /* Pods_V2rayU.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66A5CE4521706B5A009B08B2 /* Pods_V2rayU.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -146,6 +143,7 @@
|
||||
66973EB621797719001FEA1E /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; };
|
||||
66A5CE4521706B5A009B08B2 /* Pods_V2rayU.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Pods_V2rayU.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
66ACB19F21757D5B005B5881 /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
|
||||
66BC2B86228C537F00FBB716 /* PreferencePac.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencePac.xib; sourceTree = "<group>"; };
|
||||
66F411B421CA8921007AAC10 /* cmd.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = cmd.sh; sourceTree = "<group>"; };
|
||||
66FEAD45217D75FC009DECF9 /* release.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = release.sh; sourceTree = "<group>"; };
|
||||
66FEAD4F217EE14C009DECF9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ConfigWindow.xib; sourceTree = "<group>"; };
|
||||
@ -155,16 +153,12 @@
|
||||
6D6DF3C1564D0EBC5A99C9C1 /* gfwlist.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = gfwlist.txt; sourceTree = "<group>"; };
|
||||
6D6DF4CCA47DCA0A592BCE60 /* PreferenceAdvance.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferenceAdvance.xib; sourceTree = "<group>"; };
|
||||
6D6DF5345E4582EE0EBD468D /* PreferenceSubscript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferenceSubscript.swift; sourceTree = "<group>"; };
|
||||
6D6DF57E4CB6D7998F746068 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/UserRulesWindow.xib; sourceTree = "<group>"; };
|
||||
6D6DF587B6AF8CEE029E48BC /* UserRulesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserRulesWindow.swift; sourceTree = "<group>"; };
|
||||
6D6DF62A40417837EA751D88 /* PacUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PacUtils.swift; sourceTree = "<group>"; };
|
||||
6D6DF69C7CA7EBEFFE8E22D1 /* abp.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = abp.js; sourceTree = "<group>"; };
|
||||
6D6DF701C75D8D416096D717 /* PreferenceAdvance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferenceAdvance.swift; sourceTree = "<group>"; };
|
||||
6D6DF870C8E334815FBA78B2 /* PreferenceAbout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferenceAbout.swift; sourceTree = "<group>"; };
|
||||
6D6DF87840CDA04AF0E9D36E /* Scanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scanner.swift; sourceTree = "<group>"; };
|
||||
6D6DF8E42F7E29CCBEFF5468 /* tmp.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tmp.json; sourceTree = "<group>"; };
|
||||
6D6DF8F5112A8407EE959998 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = file.gitignore; path = .gitignore; sourceTree = "<group>"; };
|
||||
6D6DFBC0F08C2F7D573B93B7 /* PreferencePac.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferencePac.xib; sourceTree = "<group>"; };
|
||||
6D6DFBD3C6A7344A44DDE16D /* PreferenceSubscript.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferenceSubscript.xib; sourceTree = "<group>"; };
|
||||
6D6DFCD202C8F28474E9ED3C /* PreferenceAbout.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PreferenceAbout.xib; sourceTree = "<group>"; };
|
||||
6D6DFCE2F5044A1164CB14E3 /* tmp1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = tmp1.json; sourceTree = "<group>"; };
|
||||
@ -301,9 +295,6 @@
|
||||
664EB37B216C9A5F00B6AE0D /* Info.plist */,
|
||||
667029D121AFB86E0079EF41 /* QrcodeWindow.xib */,
|
||||
6D6DF12EA09D2D80788666D0 /* QrcodeWindow.swift */,
|
||||
6D6DF62A40417837EA751D88 /* PacUtils.swift */,
|
||||
6D6DF587B6AF8CEE029E48BC /* UserRulesWindow.swift */,
|
||||
6D6DF010124783F31646A895 /* UserRulesWindow.xib */,
|
||||
6D6DFBED570A0D1FDED0BD53 /* Preference */,
|
||||
);
|
||||
path = V2rayU;
|
||||
@ -325,7 +316,7 @@
|
||||
6D6DF870C8E334815FBA78B2 /* PreferenceAbout.swift */,
|
||||
6D6DFCD202C8F28474E9ED3C /* PreferenceAbout.xib */,
|
||||
6D6DF3151BBA6E56836AF6DE /* PreferencePac.swift */,
|
||||
6D6DFBC0F08C2F7D573B93B7 /* PreferencePac.xib */,
|
||||
66BC2B86228C537F00FBB716 /* PreferencePac.xib */,
|
||||
6D6DF5345E4582EE0EBD468D /* PreferenceSubscript.swift */,
|
||||
6D6DFBD3C6A7344A44DDE16D /* PreferenceSubscript.xib */,
|
||||
6D6DFFB29020127E034AD168 /* PreferenceGeneral.swift */,
|
||||
@ -525,13 +516,12 @@
|
||||
66F411B521CA8921007AAC10 /* cmd.sh in Resources */,
|
||||
664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */,
|
||||
66FEAD53217EE14C009DECF9 /* ConfigWindow.xib in Resources */,
|
||||
6D6DFD4A3A226788760150F8 /* UserRulesWindow.xib in Resources */,
|
||||
6D6DF872C0DECC082122D783 /* tmp.json in Resources */,
|
||||
6D6DF7C2F627A8BABECA4C32 /* tmp1.json in Resources */,
|
||||
6D6DF5F67A917F78FF652D45 /* .gitignore in Resources */,
|
||||
6D6DF75A00BCDA0C2733A718 /* PreferencePac.xib in Resources */,
|
||||
6D6DF16BC49BBF5F3D4B12CF /* PreferenceGeneral.xib in Resources */,
|
||||
6D6DFD181802BAFE2933B9C9 /* PreferenceSubscript.xib in Resources */,
|
||||
66BC2B87228C537F00FBB716 /* PreferencePac.xib in Resources */,
|
||||
6D6DFBB73E90918ED212F138 /* PreferenceAbout.xib in Resources */,
|
||||
6D6DF43A6898B0A8CB50C241 /* PreferenceAdvance.xib in Resources */,
|
||||
);
|
||||
@ -638,8 +628,6 @@
|
||||
6D6DF8BFC33F97E9AFCA5A4B /* V2rayConfig.swift in Sources */,
|
||||
6D6DF6F065067CD879201FF9 /* Scanner.swift in Sources */,
|
||||
6D6DF2CF13D9FD3C7C6492A4 /* QrcodeWindow.swift in Sources */,
|
||||
6D6DF06E32A1DC263EDF1A8E /* PacUtils.swift in Sources */,
|
||||
6D6DFB41BC9692C90A47F31B /* UserRulesWindow.swift in Sources */,
|
||||
6D6DF93B58B654D86ACC490E /* PreferenceAbout.swift in Sources */,
|
||||
6D6DF87497313615AFE3320A /* PreferencePac.swift in Sources */,
|
||||
6D6DF2F2DFB2234541488BBD /* PreferenceSubscript.swift in Sources */,
|
||||
@ -688,14 +676,6 @@
|
||||
name = ConfigWindow.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
6D6DF010124783F31646A895 /* UserRulesWindow.xib */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
6D6DF57E4CB6D7998F746068 /* Base */,
|
||||
);
|
||||
name = UserRulesWindow.xib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
|
@ -28,12 +28,11 @@ let preferencesWindowController = PreferencesWindowController(
|
||||
PreferenceGeneralViewController(),
|
||||
PreferenceAdvanceViewController(),
|
||||
PreferenceSubscriptViewController(),
|
||||
PreferencePacController(),
|
||||
PreferenceAboutController(),
|
||||
PreferencePacViewController(),
|
||||
PreferenceAboutViewController(),
|
||||
]
|
||||
)
|
||||
var qrcodeWindow = QrcodeWindowController()
|
||||
var editUserRulesWinCtrl = UserRulesWindowController()
|
||||
|
||||
// menu controller
|
||||
class MenuController: NSObject, NSMenuDelegate {
|
||||
|
@ -7,131 +7,3 @@
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
|
||||
|
||||
let PACRulesDirPath = AppResourcesPath + "/pac/"
|
||||
let PACUserRuleFilePath = PACRulesDirPath + "user-rule.txt"
|
||||
let PACFilePath = PACRulesDirPath + "pac.js"
|
||||
let PACUrl = "http://127.0.0.1:" + String(httpServerPort) + "/pac/pac.js"
|
||||
let PACAbpFile = PACRulesDirPath + "abp.js"
|
||||
let GFWListFilePath = PACRulesDirPath + "gfwlist.txt"
|
||||
let GFWListURL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"
|
||||
|
||||
// Because of LocalSocks5.ListenPort may be changed
|
||||
func GeneratePACFile() -> Bool {
|
||||
print("GeneratePACFile")
|
||||
let socks5Address = "127.0.0.1"
|
||||
|
||||
let v2ray = V2rayServer.loadSelectedItem()
|
||||
var sockPort = "1080"
|
||||
if v2ray != nil && v2ray!.isValid {
|
||||
let cfg = V2rayConfig()
|
||||
cfg.parseJson(jsonText: v2ray!.json)
|
||||
sockPort = cfg.socksPort
|
||||
}
|
||||
|
||||
// permission
|
||||
_ = shell(launchPath: "/bin/bash", arguments: ["-c", "cd " + AppResourcesPath + " && /bin/chmod -R 755 ./pac"])
|
||||
|
||||
do {
|
||||
let gfwlist = try String(contentsOfFile: GFWListFilePath, encoding: String.Encoding.utf8)
|
||||
if let data = Data(base64Encoded: gfwlist, options: .ignoreUnknownCharacters) {
|
||||
let str = String(data: data, encoding: String.Encoding.utf8)
|
||||
var lines = str!.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
// read userRules from UserDefaults
|
||||
let userRules = UserDefaults.get(forKey: .userRules)
|
||||
if userRules != nil {
|
||||
try userRules!.data(using: String.Encoding.utf8)?.write(to: URL(fileURLWithPath: PACUserRuleFilePath), options: .atomic)
|
||||
}
|
||||
|
||||
do {
|
||||
let userRuleStr = try String(contentsOfFile: PACUserRuleFilePath, encoding: String.Encoding.utf8)
|
||||
let userRuleLines = userRuleStr.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
lines = userRuleLines + lines
|
||||
} catch {
|
||||
NSLog("Not found user-rule.txt")
|
||||
}
|
||||
// Filter empty and comment lines
|
||||
lines = lines.filter({ (s: String) -> Bool in
|
||||
if s.isEmpty {
|
||||
return false
|
||||
}
|
||||
let c = s[s.startIndex]
|
||||
if c == "!" || c == "[" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
do {
|
||||
// rule lines to json array
|
||||
let rulesJsonData: Data = try JSONSerialization.data(withJSONObject: lines, options: .prettyPrinted)
|
||||
let rulesJsonStr = String(data: rulesJsonData, encoding: String.Encoding.utf8)
|
||||
|
||||
// Get raw pac js
|
||||
let jsData = try? Data(contentsOf: URL.init(fileURLWithPath: PACAbpFile))
|
||||
var jsStr = String(data: jsData!, encoding: String.Encoding.utf8)
|
||||
|
||||
// Replace rules placeholder in pac js
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__RULES__", with: rulesJsonStr!)
|
||||
// Replace __SOCKS5PORT__ palcholder in pac js
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5PORT__", with: "\(sockPort)")
|
||||
// Replace __SOCKS5ADDR__ palcholder in pac js
|
||||
var sin6 = sockaddr_in6()
|
||||
if socks5Address.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 {
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5ADDR__", with: "[\(socks5Address)]")
|
||||
} else {
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5ADDR__", with: socks5Address)
|
||||
}
|
||||
|
||||
// Write the pac js to file.
|
||||
try jsStr!.data(using: String.Encoding.utf8)?.write(to: URL(fileURLWithPath: PACFilePath), options: .atomic)
|
||||
return true
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
NSLog("Not found gfwlist.txt")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func UpdatePACFromGFWList() {
|
||||
// Make the dir if rulesDirPath is not exesited.
|
||||
if !FileManager.default.fileExists(atPath: PACRulesDirPath) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(atPath: PACRulesDirPath
|
||||
, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
Alamofire.request(GFWListURL).responseString {
|
||||
response in
|
||||
if response.result.isSuccess {
|
||||
if let v = response.result.value {
|
||||
do {
|
||||
try v.write(toFile: GFWListFilePath, atomically: true, encoding: String.Encoding.utf8)
|
||||
|
||||
if GeneratePACFile() {
|
||||
// Popup a user notification
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "PAC has been updated by latest GFW List."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Popup a user notification
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "Failed to download latest GFW List."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import Preferences
|
||||
import ServiceManagement
|
||||
import Sparkle
|
||||
|
||||
final class PreferenceAboutController: NSViewController, PreferencePane {
|
||||
final class PreferenceAboutViewController: NSViewController, PreferencePane {
|
||||
let preferencePaneIdentifier = PreferencePane.Identifier.aboutTab
|
||||
let preferencePaneTitle = "About"
|
||||
let toolbarItemIcon = NSImage(named: NSImage.infoName)!
|
||||
|
@ -6,7 +6,7 @@
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferenceAboutController" customModule="V2rayU" customModuleProvider="target">
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferenceAboutViewController" customModule="V2rayU" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="V2rayCoreVersion" destination="gws-ge-QLa" id="0Gu-lx-VkO"/>
|
||||
<outlet property="VersionLabel" destination="GfP-Xl-Rdf" id="tPf-dh-zDO"/>
|
||||
@ -112,6 +112,5 @@
|
||||
<point key="canvasLocation" x="-190" y="-220.5"/>
|
||||
</view>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<userDefaultsController representsSharedInstance="YES" id="HAt-Ds-MVV"/>
|
||||
</objects>
|
||||
</document>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferenceGeneralViewController" customModule="V2rayU" customModuleProvider="target">
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferenceAdvanceViewController" customModule="V2rayU" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="view" destination="bXz-rK-jao" id="xYY-dt-fo2"/>
|
||||
</connections>
|
||||
|
@ -52,20 +52,26 @@
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
<button horizontalHuggingPriority="500" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cPC-Na-pRr">
|
||||
<rect key="frame" x="14" y="143" width="165" height="32"/>
|
||||
<rect key="frame" x="80" y="70" width="165" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Check for Updates..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="2p9-GL-XZ9">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="checkVersion:" target="-2" id="4u0-Zb-Xfz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button horizontalHuggingPriority="500" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="liJ-Uu-8HQ">
|
||||
<rect key="frame" x="14" y="110" width="111" height="32"/>
|
||||
<rect key="frame" x="269" y="70" width="111" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Feedback..." bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QjX-NH-23u">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="goFeedback:" target="-2" id="dvI-qJ-3yN"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-143" y="-199"/>
|
||||
|
@ -6,12 +6,19 @@
|
||||
// Copyright © 2018 yanue. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import Preferences
|
||||
import ServiceManagement
|
||||
import Sparkle
|
||||
import Alamofire
|
||||
|
||||
final class PreferencePacController: NSViewController, PreferencePane {
|
||||
let PACRulesDirPath = AppResourcesPath + "/pac/"
|
||||
let PACUserRuleFilePath = PACRulesDirPath + "user-rule.txt"
|
||||
let PACFilePath = PACRulesDirPath + "pac.js"
|
||||
let PACUrl = "http://127.0.0.1:" + String(httpServerPort) + "/pac/pac.js"
|
||||
let PACAbpFile = PACRulesDirPath + "abp.js"
|
||||
let GFWListFilePath = PACRulesDirPath + "gfwlist.txt"
|
||||
let GFWListURL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"
|
||||
|
||||
final class PreferencePacViewController: NSViewController, PreferencePane {
|
||||
let preferencePaneIdentifier = PreferencePane.Identifier.pacTab
|
||||
let preferencePaneTitle = "Pac File"
|
||||
let toolbarItemIcon = NSImage(named: NSImage.bookmarksTemplateName)!
|
||||
@ -20,9 +27,181 @@ final class PreferencePacController: NSViewController, PreferencePane {
|
||||
return "PreferencePac"
|
||||
}
|
||||
|
||||
@IBOutlet weak var gfwPacListUrl: NSTextField!
|
||||
@IBOutlet var userRulesView: NSTextView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
// fix: https://github.com/sindresorhus/Preferences/issues/31
|
||||
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height);
|
||||
|
||||
let gfwUrl = UserDefaults.get(forKey: .gfwPacListUrl)
|
||||
if gfwUrl != nil {
|
||||
gfwPacListUrl.stringValue = gfwUrl!
|
||||
} else {
|
||||
gfwPacListUrl.stringValue = GFWListURL
|
||||
}
|
||||
|
||||
// read userRules from UserDefaults
|
||||
let txt = UserDefaults.get(forKey: .userRules)
|
||||
var userRuleTxt = """
|
||||
! Put user rules line by line in this file.
|
||||
! See https://adblockplus.org/en/filter-cheatsheet
|
||||
|
||||
"""
|
||||
if txt != nil {
|
||||
if txt!.count>0 {
|
||||
userRuleTxt = txt!
|
||||
}
|
||||
} else {
|
||||
let str = try? String(contentsOfFile: PACUserRuleFilePath, encoding: String.Encoding.utf8)
|
||||
if str!.count>0 {
|
||||
userRuleTxt = str!
|
||||
}
|
||||
}
|
||||
userRulesView.string = userRuleTxt
|
||||
}
|
||||
|
||||
@IBAction func updatePac(_ sender: Any) {
|
||||
if let str = userRulesView?.string {
|
||||
do {
|
||||
// save user rules into UserDefaults
|
||||
UserDefaults.set(forKey: .userRules, value: str)
|
||||
print("updatePac str",str)
|
||||
try str.data(using: String.Encoding.utf8)?.write(to: URL(fileURLWithPath: PACUserRuleFilePath), options: .atomic)
|
||||
|
||||
UpdatePACFromGFWList()
|
||||
|
||||
if GeneratePACFile() {
|
||||
// Popup a user notification
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "PAC has been updated by User Rules."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
} else {
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "It's failed to update PAC by User Rules."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Because of LocalSocks5.ListenPort may be changed
|
||||
func GeneratePACFile() -> Bool {
|
||||
let socks5Address = "127.0.0.1"
|
||||
|
||||
let v2ray = V2rayServer.loadSelectedItem()
|
||||
var sockPort = "1080"
|
||||
if v2ray != nil && v2ray!.isValid {
|
||||
let cfg = V2rayConfig()
|
||||
cfg.parseJson(jsonText: v2ray!.json)
|
||||
sockPort = cfg.socksPort
|
||||
}
|
||||
|
||||
// permission
|
||||
_ = shell(launchPath: "/bin/bash", arguments: ["-c", "cd " + AppResourcesPath + " && /bin/chmod -R 755 ./pac"])
|
||||
|
||||
do {
|
||||
let gfwlist = try String(contentsOfFile: GFWListFilePath, encoding: String.Encoding.utf8)
|
||||
if let data = Data(base64Encoded: gfwlist, options: .ignoreUnknownCharacters) {
|
||||
let str = String(data: data, encoding: String.Encoding.utf8)
|
||||
var lines = str!.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
// read userRules from UserDefaults
|
||||
let userRules = UserDefaults.get(forKey: .userRules)
|
||||
if userRules != nil {
|
||||
try userRules!.data(using: String.Encoding.utf8)?.write(to: URL(fileURLWithPath: PACUserRuleFilePath), options: .atomic)
|
||||
}
|
||||
|
||||
do {
|
||||
let userRuleStr = try String(contentsOfFile: PACUserRuleFilePath, encoding: String.Encoding.utf8)
|
||||
let userRuleLines = userRuleStr.components(separatedBy: CharacterSet.newlines)
|
||||
|
||||
lines = userRuleLines + lines
|
||||
} catch {
|
||||
NSLog("Not found user-rule.txt")
|
||||
}
|
||||
// Filter empty and comment lines
|
||||
lines = lines.filter({ (s: String) -> Bool in
|
||||
if s.isEmpty {
|
||||
return false
|
||||
}
|
||||
let c = s[s.startIndex]
|
||||
if c == "!" || c == "[" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
do {
|
||||
// rule lines to json array
|
||||
let rulesJsonData: Data = try JSONSerialization.data(withJSONObject: lines, options: .prettyPrinted)
|
||||
let rulesJsonStr = String(data: rulesJsonData, encoding: String.Encoding.utf8)
|
||||
|
||||
// Get raw pac js
|
||||
let jsData = try? Data(contentsOf: URL.init(fileURLWithPath: PACAbpFile))
|
||||
var jsStr = String(data: jsData!, encoding: String.Encoding.utf8)
|
||||
|
||||
// Replace rules placeholder in pac js
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__RULES__", with: rulesJsonStr!)
|
||||
// Replace __SOCKS5PORT__ palcholder in pac js
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5PORT__", with: "\(sockPort)")
|
||||
// Replace __SOCKS5ADDR__ palcholder in pac js
|
||||
var sin6 = sockaddr_in6()
|
||||
if socks5Address.withCString({ cstring in inet_pton(AF_INET6, cstring, &sin6.sin6_addr) }) == 1 {
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5ADDR__", with: "[\(socks5Address)]")
|
||||
} else {
|
||||
jsStr = jsStr!.replacingOccurrences(of: "__SOCKS5ADDR__", with: socks5Address)
|
||||
}
|
||||
|
||||
// Write the pac js to file.
|
||||
try jsStr!.data(using: String.Encoding.utf8)?.write(to: URL(fileURLWithPath: PACFilePath), options: .atomic)
|
||||
return true
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} catch {
|
||||
NSLog("Not found gfwlist.txt")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func UpdatePACFromGFWList() {
|
||||
// Make the dir if rulesDirPath is not exesited.
|
||||
if !FileManager.default.fileExists(atPath: PACRulesDirPath) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(atPath: PACRulesDirPath
|
||||
, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
Alamofire.request(GFWListURL).responseString {
|
||||
response in
|
||||
if response.result.isSuccess {
|
||||
if let v = response.result.value {
|
||||
do {
|
||||
try v.write(toFile: GFWListFilePath, atomically: true, encoding: String.Encoding.utf8)
|
||||
|
||||
if GeneratePACFile() {
|
||||
// Popup a user notification
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "PAC has been updated by latest GFW List."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Popup a user notification
|
||||
let notification = NSUserNotification()
|
||||
notification.title = "Failed to download latest GFW List."
|
||||
NSUserNotificationCenter.default.deliver(notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
76
V2rayU/Preference/PreferencePac.xib
Executable file → Normal file
76
V2rayU/Preference/PreferencePac.xib
Executable file → Normal file
@ -6,8 +6,10 @@
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferenceGeneralViewController" customModule="V2rayU" customModuleProvider="target">
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PreferencePacViewController" customModule="V2rayU" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="gfwPacListUrl" destination="zr7-bd-EAE" id="Bb8-mK-cmI"/>
|
||||
<outlet property="userRulesView" destination="TVW-6s-N8F" id="f19-R4-Xf5"/>
|
||||
<outlet property="view" destination="bXz-rK-jao" id="xYY-dt-fo2"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@ -17,48 +19,53 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="JT2-vd-Ocf">
|
||||
<rect key="frame" x="0.0" y="258" width="460" height="102"/>
|
||||
<rect key="frame" x="0.0" y="238" width="460" height="122"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" ambiguous="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dD5-t7-MtS">
|
||||
<rect key="frame" x="6" y="73" width="192" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="188" id="meM-bk-dCu"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="GFW List URL:" id="L8s-Y6-NP1">
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dD5-t7-MtS">
|
||||
<rect key="frame" x="18" y="79" width="192" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="GFW List URL" id="L8s-Y6-NP1">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" ambiguous="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zr7-bd-EAE">
|
||||
<rect key="frame" x="8" y="20" width="384" height="45"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="45" id="XJO-g5-kGc"/>
|
||||
</constraints>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zr7-bd-EAE">
|
||||
<rect key="frame" x="20" y="20" width="420" height="45"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="RXK-Mf-gKW">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<binding destination="-2" name="displayPatternValue1" keyPath="self.gfwPacListUrl" id="Mxg-5a-CDL">
|
||||
<dictionary key="options">
|
||||
<string key="NSDisplayPattern">%{value1}@</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Cg-gM-BHl">
|
||||
<rect key="frame" x="243" y="74" width="203" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Update Pac From GFW List" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="fkx-pu-mTv">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="updatePac:" target="-2" id="0Ka-zt-S7w"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</customView>
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="8NJ-ru-j3U">
|
||||
<rect key="frame" x="0.0" y="30" width="460" height="228"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="460" height="238"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LeF-Sd-TXL">
|
||||
<rect key="frame" x="18" y="188" width="192" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="User Rules:" id="W0g-B7-neT">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<scrollView fixedFrame="YES" horizontalLineScroll="10" horizontalPageScroll="10" verticalLineScroll="10" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9KM-Hr-5go">
|
||||
<rect key="frame" x="20" y="2" width="420" height="178"/>
|
||||
<rect key="frame" x="20" y="20" width="420" height="178"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="KKI-Gt-Jbl">
|
||||
<rect key="frame" x="1" y="1" width="418" height="176"/>
|
||||
@ -84,20 +91,17 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LeF-Sd-TXL">
|
||||
<rect key="frame" x="18" y="206" width="192" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" title="User Rules" id="W0g-B7-neT">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
</customView>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ug9-RB-78F">
|
||||
<rect key="frame" x="371" y="-3" width="81" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="save" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="oBz-VP-htp">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="-130" y="-187"/>
|
||||
</view>
|
||||
|
@ -17,14 +17,14 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mta-JC-Ywa">
|
||||
<rect key="frame" x="20" y="85" width="420" height="226"/>
|
||||
<rect key="frame" x="20" y="38" width="420" height="273"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" id="4aC-gI-mNs">
|
||||
<rect key="frame" x="1" y="0.0" width="418" height="225"/>
|
||||
<rect key="frame" x="1" y="0.0" width="418" height="272"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnSelection="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="yUk-I2-XZb" viewBased="YES" id="fYa-dn-wCU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="418" height="200"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="418" height="247"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
@ -123,9 +123,9 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3pd-DD-jIz">
|
||||
<rect key="frame" x="300" y="316" width="146" height="32"/>
|
||||
<rect key="frame" x="308" y="316" width="131" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="update servers ..." bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ZPU-gS-0li">
|
||||
<buttonCell key="cell" type="push" title="update servers" bezelStyle="rounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ZPU-gS-0li">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
|
@ -29,6 +29,8 @@ extension UserDefaults {
|
||||
case runMode
|
||||
// use rules
|
||||
case userRules
|
||||
// gfw pac list url
|
||||
case gfwPacListUrl
|
||||
}
|
||||
|
||||
static func setBool(forKey key: KEY, value: Bool) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user