Merge branch 'import-json-configs' into develop

This commit is contained in:
qinyuhang
2016-08-28 08:28:15 +08:00
10 changed files with 2454 additions and 2071 deletions
+12 -4
View File
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
0880CE401D6FE6D900BD39E2 /* example-gui-config.json in Resources */ = {isa = PBXBuildFile; fileRef = 0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */; };
0880CE421D6FF7F600BD39E2 /* BunchImportUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */; };
088EC3971D5F5B8600E40791 /* whitelist.pac in Resources */ = {isa = PBXBuildFile; fileRef = 088EC3961D5F5B8600E40791 /* whitelist.pac */; };
088EC3991D5F5BA300E40791 /* whiteiplist.pac in Resources */ = {isa = PBXBuildFile; fileRef = 088EC3981D5F5BA300E40791 /* whiteiplist.pac */; };
258E511BA910B0521B24DAB8 /* Pods_ShadowsocksX_NG.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 283ED1A8E9B711AC65670031 /* Pods_ShadowsocksX_NG.framework */; };
@@ -90,6 +92,10 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
085641E91D7188C400116B27 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
085641EB1D71A48700116B27 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = "<group>"; };
0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "example-gui-config.json"; sourceTree = "<group>"; };
0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BunchImportUtils.swift; sourceTree = "<group>"; };
088EC3961D5F5B8600E40791 /* whitelist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whitelist.pac; sourceTree = "<group>"; };
088EC3981D5F5BA300E40791 /* whiteiplist.pac */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = whiteiplist.pac; sourceTree = "<group>"; };
08AF56C01D6AFA7C00DC4F46 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/PreferencesWindowController.strings"; sourceTree = "<group>"; };
@@ -115,12 +121,10 @@
9B0BFFF41D0460A70040E62B /* ShadowsocksX-NGTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ShadowsocksX-NGTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
9B0BFFF81D0460A70040E62B /* ShadowsocksX_NGTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksX_NGTests.swift; sourceTree = "<group>"; };
9B0BFFFA1D0460A70040E62B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9B0D55451D2CC1B800A4A8E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/MainMenu.strings"; sourceTree = "<group>"; };
9B0D554A1D2CC85E00A4A8E2 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ProxyPreferencesController.strings"; sourceTree = "<group>"; };
9B0D554B1D2CC87400A4A8E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ProxyPreferencesController.xib; sourceTree = "<group>"; };
9B172A5D1D0ACEA100B87B9A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/AdvPreferencesWindowController.strings"; sourceTree = "<group>"; };
9B172A601D0ADA5B00B87B9A /* genstrings.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = genstrings.py; sourceTree = "<group>"; };
9B172A6B1D0ADDDD00B87B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
9B172A6D1D0ADDE800B87B9A /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
9B2491B51D0ACC3A003BBECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindowController.xib; sourceTree = "<group>"; };
9B2491B81D0ACC3E003BBECC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/AdvPreferencesWindowController.xib; sourceTree = "<group>"; };
@@ -225,6 +229,7 @@
9B3FFF351D08CF110019A709 /* jquery.min.js */,
9B3FFF361D08CF110019A709 /* qrcode.min.js */,
9B3FFF371D08CF110019A709 /* qrcode.htm */,
0880CE3F1D6FE6D900BD39E2 /* example-gui-config.json */,
9B3FFF281D08A1DF0019A709 /* user-rule.txt */,
088EC3961D5F5B8600E40791 /* whitelist.pac */,
088EC3981D5F5BA300E40791 /* whiteiplist.pac */,
@@ -284,6 +289,7 @@
9BEEF06F1D04DDB100FC52B3 /* ServerProfileManager.swift */,
9BEEF0771D04FE8A00FC52B3 /* LaunchAgentUtils.swift */,
9B3FFF0C1D05FEB30019A709 /* Utils.swift */,
0880CE411D6FF7F600BD39E2 /* BunchImportUtils.swift */,
9B3FFF201D08826E0019A709 /* PACUtils.swift */,
9B3FFF131D0705810019A709 /* Notifications.swift */,
9B3FFF1D1D0732660019A709 /* Utils.m */,
@@ -467,6 +473,7 @@
9BEEF06A1D04D4D500FC52B3 /* start_ss_local.sh in Resources */,
9B3FFF391D08CF110019A709 /* qrcode.min.js in Resources */,
9B3FFF3A1D08CF110019A709 /* qrcode.htm in Resources */,
0880CE401D6FE6D900BD39E2 /* example-gui-config.json in Resources */,
9BEEF06B1D04D4D500FC52B3 /* stop_ss_local.sh in Resources */,
9B3FFF341D08CEF70019A709 /* SWBQRCodeWindowController.xib in Resources */,
9BEEF06C1D04D4D500FC52B3 /* reload_conf_ss_local.sh in Resources */,
@@ -638,6 +645,7 @@
9BEEF06E1D04DCE400FC52B3 /* ServerProfile.swift in Sources */,
9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */,
9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */,
0880CE421D6FF7F600BD39E2 /* BunchImportUtils.swift in Sources */,
9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */,
9BA04B231D23D5A5005AAD7F /* ProxyConfTool.m in Sources */,
9BEEF0781D04FE8A00FC52B3 /* LaunchAgentUtils.swift in Sources */,
@@ -681,7 +689,7 @@
isa = PBXVariantGroup;
children = (
9B0BFFED1D0460A70040E62B /* Base */,
9B0D55451D2CC1B800A4A8E2 /* zh-Hans */,
085641EB1D71A48700116B27 /* zh-Hans */,
);
name = MainMenu.xib;
sourceTree = "<group>";
@@ -698,8 +706,8 @@
9B172A6C1D0ADDDD00B87B9A /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
9B172A6B1D0ADDDD00B87B9A /* Base */,
9B172A6D1D0ADDE800B87B9A /* zh-Hans */,
085641E91D7188C400116B27 /* Base */,
);
name = Localizable.strings;
sourceTree = "<group>";
+24 -2
View File
@@ -36,6 +36,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
@IBOutlet weak var serversMenuItem: NSMenuItem!
@IBOutlet var showQRCodeMenuItem: NSMenuItem!
@IBOutlet var scanQRCodeMenuItem: NSMenuItem!
@IBOutlet var showBunchJsonExampleFileItem: NSMenuItem!
@IBOutlet var importBunchJsonFileItem: NSMenuItem!
@IBOutlet var exportAllServerProfileItem: NSMenuItem!
@IBOutlet var serversPreferencesMenuItem: NSMenuItem!
@IBOutlet weak var lanchAtLoginMenuItem: NSMenuItem!
@@ -257,6 +260,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
@IBAction func scanQRCodeFromScreen(sender: NSMenuItem) {
ScanQRCodeOnScreen()
}
@IBAction func showBunchJsonExampleFile(sender: NSMenuItem) {
showExampleConfigFile()
}
@IBAction func importBunchJsonFile(sender: NSMenuItem) {
importConfigFile()
//updateServersMenu()//not working
}
@IBAction func exportAllServerProfile(sender: NSMenuItem) {
exportConfigFile()
}
@IBAction func toggleLaunghAtLogin(sender: NSMenuItem) {
launchAtLoginController.launchAtLogin = !launchAtLoginController.launchAtLogin;
@@ -397,7 +413,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
whiteListDomainMenuItem.state = 0
whiteListIPMenuItem.state = 0
} else if mode == "whiteListDomain" {
proxyMenuItem.title = "Proxy - WhiteList Domain".localized
proxyMenuItem.title = "Proxy - White List Domain".localized
autoModeMenuItem.state = 0
globalModeMenuItem.state = 0
manualModeMenuItem.state = 0
@@ -405,7 +421,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
whiteListDomainMenuItem.state = 1
whiteListIPMenuItem.state = 0
} else if mode == "whiteListIP" {
proxyMenuItem.title = "Proxy - WhiteList IP".localized
proxyMenuItem.title = "Proxy - White List IP".localized
autoModeMenuItem.state = 0
globalModeMenuItem.state = 0
manualModeMenuItem.state = 0
@@ -437,6 +453,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
let showQRItem = showQRCodeMenuItem
let scanQRItem = scanQRCodeMenuItem
let preferencesItem = serversPreferencesMenuItem
let showBunch = showBunchJsonExampleFileItem
let importBuntch = importBunchJsonFileItem
let exportAllServer = exportAllServerProfileItem
var i = 0
for p in mgr.profiles {
@@ -463,6 +482,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
}
serversMenuItem.submenu?.addItem(showQRItem)
serversMenuItem.submenu?.addItem(scanQRItem)
serversMenuItem.submenu?.addItem(showBunch)
serversMenuItem.submenu?.addItem(importBuntch)
serversMenuItem.submenu?.addItem(exportAllServer)
serversMenuItem.submenu?.addItem(NSMenuItem.separatorItem())
serversMenuItem.submenu?.addItem(preferencesItem)
}
+36 -17
View File
@@ -1,27 +1,39 @@
/*
* SHARED STRINGS
*/
/*
* ./PACUtils.swift
* ./ShadowsocksX-NG/PACUtils.swift
*/
"PAC has been updated by latest GFW List." = "PAC has been updated by latest GFW List.";
"Failed to download latest GFW List." = "Failed to download latest GFW List.";
"White List updated succeed." = "White List updated succeed.";
"White List update succeed." = "White List update succeed.";
"Failed to download latest White List update succeed." = "Failed to download latest White List update succeed.";
/*
* ./PreferencesWindowController.swift
* ./ShadowsocksX-NG/BunchImportUtils.swift
*/
"New Server" = "New Server";
"Import Server Profile succeed!" = "Import Server Profile succeed!";
"Successful import \(configsCount) items" = "Successful import \(configsCount) items";
"Import Server Profile failed!" = "Import Server Profile failed!";
"Invalid config file!" = "Invalid config file!";
/*
* ./AppDelegate.swift
* ./ShadowsocksX-NG/AppDelegate.swift
*/
"Add Shadowsocks Server Profile" = "Add Shadowsocks Server Profile";
@@ -36,6 +48,16 @@
"No current server profile." = "No current server profile.";
"Proxy - Auto By PAC" = "Proxy - Auto By PAC";
"Proxy - Global" = "Proxy - Global";
"Proxy - Manual" = "Proxy - Manual";
"Proxy - White List Domain" = "Proxy - White List Domain";
"Proxy - White List IP" = "Proxy - White List IP";
"Shadowsocks: On" = "Shadowsocks: On";
"Turn Shadowsocks Off" = "Turn Shadowsocks Off";
@@ -44,20 +66,17 @@
"Turn Shadowsocks On" = "Turn Shadowsocks On";
"Proxy - Auto By PAC" = "Proxy - Auto By PAC";
/*
* ./ShadowsocksX-NG/PreferencesWindowController.swift
*/
"Proxy - Global" = "Proxy - Global";
"New Server" = "New Server";
"Proxy - Manual" = "Proxy - Manual";
/*
* ./ShadowsocksX-NG/UserRulesController.swift
*/
"Proxy - WhiteList" = "Proxy - WhiteList";
"PAC has been updated by User Rules." = "PAC has been updated by User Rules.";
"Proxy - WhiteList Domain" = "Proxy - WhiteList Domain";
"It's failed to update PAC by User Rules." = "It's failed to update PAC by User Rules.";
"Proxy - WhiteList IP" = "Proxy - WhiteList IP";
"White List Mode" = "White List Mode";
"White List Domain" = "White List Domain";
"White List IP" = "White List IP";
+22 -1
View File
@@ -15,7 +15,9 @@
<connections>
<outlet property="RunningStatusMenuItem" destination="fzk-mE-CEV" id="R4x-gK-Qcw"/>
<outlet property="autoModeMenuItem" destination="r07-Gu-aEz" id="9aH-pQ-Rgi"/>
<outlet property="exportAllServerProfileItem" destination="6k0-gn-DQv" id="1xA-cd-5Ia"/>
<outlet property="globalModeMenuItem" destination="Mw3-Jm-eXA" id="ar5-Yx-3ze"/>
<outlet property="importBunchJsonFileItem" destination="T9g-gy-gvv" id="GW7-ii-U1j"/>
<outlet property="lanchAtLoginMenuItem" destination="eUq-p7-ICK" id="w4p-0c-DZn"/>
<outlet property="manualModeMenuItem" destination="8PR-gs-c5N" id="9qz-mU-5kt"/>
<outlet property="proxyMenuItem" destination="diI-fB-Rss" id="Qjk-9U-3Qy"/>
@@ -23,6 +25,7 @@
<outlet property="scanQRCodeMenuItem" destination="Qe6-bF-paT" id="XHa-pa-nCa"/>
<outlet property="serversMenuItem" destination="u5M-hQ-VSc" id="8gp-SY-Y4U"/>
<outlet property="serversPreferencesMenuItem" destination="M5r-E7-44f" id="voe-SX-k6a"/>
<outlet property="showBunchJsonExampleFileItem" destination="pdy-JE-50Q" id="aWi-DB-deq"/>
<outlet property="showQRCodeMenuItem" destination="R6A-96-Zcb" id="XHz-pz-nCz"/>
<outlet property="statusMenu" destination="Hob-KD-bx9" id="clA-ZW-0pT"/>
<outlet property="toggleRunningMenuItem" destination="GSu-Tf-StS" id="XHw-pU-nCa"/>
@@ -124,12 +127,30 @@
<action selector="showQRCodeForCurrentServer:" target="Voe-Tx-rLC" id="t45-Zk-cai"/>
</connections>
</menuItem>
<menuItem title="Scan QR Code From Screen ..." id="Qe6-bF-paT">
<menuItem title="Scan QR Code From Screen..." id="Qe6-bF-paT">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="scanQRCodeFromScreen:" target="Voe-Tx-rLC" id="zQZ-IT-H4a"/>
</connections>
</menuItem>
<menuItem title="Show Bunch Json Example File..." id="pdy-JE-50Q">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="showBunchJsonExampleFile:" target="Voe-Tx-rLC" id="2fR-af-bNb"/>
</connections>
</menuItem>
<menuItem title="Import Bunch Json File..." id="T9g-gy-gvv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="importBunchJsonFile:" target="Voe-Tx-rLC" id="ptm-YK-H93"/>
</connections>
</menuItem>
<menuItem title="Export All Server To Json..." id="6k0-gn-DQv">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="exportAllServerProfile:" target="Voe-Tx-rLC" id="C5A-Pp-tYo"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="6sL-A4-S7N"/>
<menuItem title="Server Preferences..." id="M5r-E7-44f">
<modifierMask key="keyEquivalentModifierMask"/>
+141
View File
@@ -0,0 +1,141 @@
//
// BunchImportUtils.swift
// ShadowsocksX-NG
//
// Created by 秦宇航 on 16/8/26.
// Copyright © 2016年 qiuyuzhou. All rights reserved.
//
import Foundation
var profileMgr: ServerProfileManager!
//Todo: function 1 showExampleFile, 调用fileManager 拷贝 json 到Downloads文件夹,然后打开Downloads文件夹
//拷贝json配置文件到~/Downloads文件夹
func showExampleConfigFile() {
//copy file to ~/Downloads folder
let filePath:String = NSBundle.mainBundle().bundlePath + "/Contents/Resources/example-gui-config.json"
let fileMgr = NSFileManager.defaultManager()
let dataPath = NSHomeDirectory().stringByAppendingString("/Downloads")
let destPath = dataPath + "/example-gui-config.json"
//检测文件是否已经存在,如果存在直接用sharedWorkspace显示
if fileMgr.fileExistsAtPath(destPath) {
NSWorkspace.sharedWorkspace().selectFile(destPath, inFileViewerRootedAtPath: dataPath)
}else{
try! fileMgr.copyItemAtPath(filePath, toPath: destPath)
NSWorkspace.sharedWorkspace().selectFile(destPath, inFileViewerRootedAtPath: dataPath)
}
}
//调用fileManager,读取json文件,对configs for循环调用 profileManager 生成 profile并保存
func importConfigFile() {
let openPanel = NSOpenPanel()
openPanel.title = "Choose Config Json File".localized
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = false
openPanel.canCreateDirectories = false
openPanel.canChooseFiles = true
openPanel.beginWithCompletionHandler { (result) -> Void in
if (result == NSFileHandlingPanelOKButton && (openPanel.URL) != nil) {
let fileManager = NSFileManager.defaultManager()
let filePath:String = (openPanel.URL?.path!)!
if (fileManager.fileExistsAtPath(filePath) && filePath.hasSuffix("json")) {
let data = fileManager.contentsAtPath(filePath)
let readString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
let readStringData = readString.dataUsingEncoding(NSUTF8StringEncoding)
let jsonArr1 = try! NSJSONSerialization.JSONObjectWithData(readStringData!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
for item in jsonArr1.objectForKey("configs") as! [[String: AnyObject]]{
let profile = ServerProfile()
var profileMgr: ServerProfileManager!
profileMgr = ServerProfileManager.instance
profile.serverHost = item["server"] as! String
profile.serverPort = UInt16((item["server_port"]?.integerValue)!)
profile.method = item["method"] as! String
profile.password = item["password"] as! String
profile.remark = item["remarks"] as! String
if (item["obfs"] != nil) {
profile.ssrObfs = item["obfs"] as! String
profile.ssrProtocol = item["protocol"] as! String
if (item["obfsparam"] != nil){
profile.ssrObfsParam = item["obfsparam"] as! String
}
if (item["protocolparam"] != nil){
profile.ssrProtocolParam = item["protocolparam"] as! String
}
}
profileMgr.profiles.append(profile)
profileMgr.save()
NSNotificationCenter.defaultCenter().postNotificationName(NOTIFY_SERVER_PROFILES_CHANGED, object: nil)
}
let configsCount = jsonArr1.objectForKey("configs")?.count
let notification = NSUserNotification()
notification.title = "Import Server Profile succeed!".localized
notification.informativeText = "Successful import \(configsCount) items".localized
NSUserNotificationCenter.defaultUserNotificationCenter()
.deliverNotification(notification)
}else{
let notification = NSUserNotification()
notification.title = "Import Server Profile failed!".localized
notification.informativeText = "Invalid config file!".localized
NSUserNotificationCenter.defaultUserNotificationCenter()
.deliverNotification(notification)
return
}
}
}
}
func exportConfigFile() {
//读取example文件,删掉configs里面的配置,再用NSDictionary填充到configs里面
profileMgr = ServerProfileManager.instance
let fileManager = NSFileManager.defaultManager()
let filePath:String = NSBundle.mainBundle().bundlePath + "/Contents/Resources/example-gui-config.json"
let data = fileManager.contentsAtPath(filePath)
let readString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
let readStringData = readString.dataUsingEncoding(NSUTF8StringEncoding)
let jsonArr1 = try! NSJSONSerialization.JSONObjectWithData(readStringData!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
var configsArray:NSMutableArray = []
for profile in profileMgr.profiles{
var configProfile:NSMutableDictionary = [:]
//standard ss profile
configProfile.setValue(1, forKey: "enable")
configProfile.setValue(profile.serverHost, forKey: "server")
configProfile.setValue(NSNumber(unsignedShort:profile.serverPort), forKey: "server_port")//not work
configProfile.setValue(profile.password, forKey: "password")
configProfile.setValue(profile.method, forKey: "method")
configProfile.setValue(profile.remark, forKey: "remarks")
configProfile.setValue(profile.remark.dataUsingEncoding(NSUTF8StringEncoding)?.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0)), forKey: "remarks_base64")
//ssr
if 1 == 1 {
configProfile.setValue(profile.ssrObfs, forKey: "obfs")
configProfile.setValue(profile.ssrProtocol, forKey: "protocol")
if 2 == 2 {
configProfile.setValue(profile.ssrObfsParam, forKey: "obfsparam")
}
if 3 == 3 {
configProfile.setValue(profile.ssrProtocolParam, forKey: "protoclparam")
}
}
configsArray.addObject(configProfile)
}
jsonArr1.setValue(configsArray, forKey: "configs")
let jsonData = try! NSJSONSerialization.dataWithJSONObject(jsonArr1, options: NSJSONWritingOptions.PrettyPrinted)
let jsonString = NSString(data: jsonData, encoding: NSUTF8StringEncoding)! as String
let savePanel = NSSavePanel()
savePanel.title = "Export Config Json File".localized
savePanel.canCreateDirectories = true
savePanel.allowedFileTypes = ["json"]
savePanel.nameFieldStringValue = "export.json"
savePanel.beginWithCompletionHandler { (result) -> Void in
if (result == NSFileHandlingPanelOKButton && (savePanel.URL) != nil) {
//write jsonArr1 back to file
try! jsonString.writeToFile((savePanel.URL?.path)!, atomically: true, encoding: NSUTF8StringEncoding)
}
}
}
@@ -150,7 +150,10 @@ class PreferencesWindowController: NSWindowController
if oldProfileIndex >= 0 {
let oldProfile = profileMgr.profiles[oldProfileIndex]
profilesTableView.beginUpdates()
let newProfile = ServerProfile.fromDictionary(oldProfile.toDictionary())
var newProfile = ServerProfile()
let newUUID = newProfile.uuid
newProfile = ServerProfile.fromDictionary(oldProfile.toDictionary())//here 因为UUID重复了
newProfile.uuid = newUUID
profileMgr.profiles.append(newProfile)
let index = NSIndexSet(index: profileMgr.profiles.count-1)
profilesTableView.insertRowsAtIndexes(index, withAnimation: .EffectFade)
@@ -158,6 +161,8 @@ class PreferencesWindowController: NSWindowController
self.profilesTableView.selectRowIndexes(index, byExtendingSelection: false)
profilesTableView.endUpdates()
updateProfileBoxVisible()
NSNotificationCenter.defaultCenter()
.postNotificationName(NOTIFY_SERVER_PROFILES_CHANGED, object: nil)
}
}
+52
View File
@@ -0,0 +1,52 @@
{
"index": 0,
"random": false,
"global": false,
"enabled": true,
"shareOverLan": false,
"isDefault": false,
"localPort": 1080,
"pacUrl": null,
"useOnlinePac": false,
"reconnectTimes": 3,
"randomAlgorithm": 0,
"TTL": 0,
"proxyEnable": false,
"proxyType": 0,
"proxyHost": null,
"proxyPort": 0,
"proxyAuthUser": null,
"proxyAuthPass": null,
"authUser": null,
"authPass": null,
"autoban": false,
"configs": [{
"remarks": "example",
"server": "abc.xyz",
"server_port": 1234,
"method": "rc4-md5",
"obfs": "tls1.2_ticket_auth",
"obfsparam": "baidu.com",
"remarks_base64": "ZXhhbXBsZQ==",
"password": "passwd",
"tcp_over_udp": false,
"udp_over_tcp": false,
"protocol": "auth_sha1_v2",
"obfs_udp": false,
"enable": true
},{
"remarks": "example2",
"server": "xyz.xyz",
"server_port": 1234,
"method": "rc4-md5",
"obfs": "tls1.2_ticket_auth",
"obfsparam": "baidu.com",
"remarks_base64": "ZXhhbXBsZTI=",
"password": "passwd",
"tcp_over_udp": false,
"udp_over_tcp": false,
"protocol": "auth_sha1_v2",
"obfs_udp": false,
"enable": true
}]
}
+2078 -1986
View File
File diff suppressed because it is too large Load Diff
@@ -9,7 +9,7 @@
*/
/*
* ./PACUtils.swift
* ./ShadowsocksX-NG/PACUtils.swift
*/
"PAC has been updated by latest GFW List." = "已经使用最新的 GFW List 更新PAC";
@@ -21,25 +21,45 @@
"Failed to download latest White List update succeed." = "下载白名单失败";
/*
* ./PreferencesWindowController.swift
* ./ShadowsocksX-NG/BunchImportUtils.swift
*/
"New Server" = "新服务器";
"Import Server Profile succeed!" = "导入服务器配置文件成功!";
"Successful import \(configsCount) items" = "成功导入 \(configsCount) 个纪录";
"Import Server Profile failed!" = "导入服务器配置文件失败!";
"Invalid config file!" = "配置文件无效!";
/*
* ./AppDelegate.swift
* ./ShadowsocksX-NG/AppDelegate.swift
*/
"Add Shadowsocks Server Profile" = "已添加新Shaodwsocks服务器配置";
"By scan QR Code" = "通过扫描二维码";
"By Handle SS URL" = "处理 SS URL";
" Encription Method: \(profile.method)" = " 加密方法: \(profile.method)";
"Current server profile is not valid." = "当前服务器配置无效";
"No current server profile." = "未设置当前服务器配置";
"Proxy - Auto By PAC" = "代理 - PAC自动";
"Proxy - Global" = "代理 - 全局";
"Proxy - Manual" = "代理 - 手动";
"Proxy - White List" = "代理 - 白名单";
"Proxy - White List Domain" = "代理 - 域名白名单";
"Proxy - White List IP" = "代理 - IP白名单";
"Shadowsocks: On" = "Shadowsocks: On";
"Turn Shadowsocks Off" = "关闭 Shadowsocks";
@@ -48,20 +68,17 @@
"Turn Shadowsocks On" = "打开 Shadowsocks";
"Proxy - Auto By PAC" = "代理 - PAC自动";
/*
* ./ShadowsocksX-NG/PreferencesWindowController.swift
*/
"Proxy - Global" = "代理 - 全局";
"New Server" = "新服务器";
"Proxy - Manual" = "代理 - 手动";
/*
* ./ShadowsocksX-NG/UserRulesController.swift
*/
"Proxy - WhiteList" = "代理 - 白名单";
"PAC has been updated by User Rules." = "PAC has been updated by User Rules.";
"Proxy - WhiteList Domain" = "代理 - 域名白名单";
"It's failed to update PAC by User Rules." = "It's failed to update PAC by User Rules.";
"Proxy - WhiteList IP" = "代理 - IP白名单";
"White List Mode" = "白名单模式";
"White List Domain" = "域名白名单";
"White List IP" = "IP白名单";
+50 -44
View File
@@ -1,84 +1,90 @@
/* Class = "NSMenuItem"; title = "应用用户自定规则到 PAC"; ObjectID = "6qf-cg-HXc"; */
"6qf-cg-HXc.title" = "应用用户自定规则到 PAC";
/* Class = "NSMenuItem"; title = "Export All Server To Json..."; ObjectID = "6k0-gn-DQv"; */
"6k0-gn-DQv.title" = "导出全部服务器配置...";
/* Class = "NSMenuItem"; title = "手动模式"; ObjectID = "8PR-gs-c5N"; */
/* Class = "NSMenuItem"; title = "Manual Mode"; ObjectID = "8PR-gs-c5N"; */
"8PR-gs-c5N.title" = "手动模式";
/* Class = "NSMenu"; title = "服务器"; ObjectID = "9Y1-db-3HK"; */
/* Class = "NSMenu"; title = "Servers"; ObjectID = "9Y1-db-3HK"; */
"9Y1-db-3HK.title" = "服务器";
/* Class = "NSMenuItem"; title = "打开 ShadowsocksX"; ObjectID = "GSu-Tf-StS"; */
"GSu-Tf-StS.title" = "打开 ShadowsocksX";
/* Class = "NSMenuItem"; title = "Turn ShadowsocksX On"; ObjectID = "GSu-Tf-StS"; */
"GSu-Tf-StS.title" = "打开ShadowsocksX";
/* Class = "NSMenu"; title = "ShadowsocksX-NG"; ObjectID = "Hob-KD-bx9"; */
"Hob-KD-bx9.title" = "ShadowsocksX-NG";
/* Class = "NSMenuItem"; title = "显示日志..."; ObjectID = "Jfy-sf-Fhl"; */
/* Class = "NSMenuItem"; title = "Show Logs..."; ObjectID = "Jfy-sf-Fhl"; */
"Jfy-sf-Fhl.title" = "显示日志...";
/* Class = "NSMenuItem"; title = "关于"; ObjectID = "LgB-6g-Gba"; */
/* Class = "NSMenuItem"; title = "White List Domain"; ObjectID = "L27-aH-Wwl"; */
"L27-aH-Wwl.title" = "域名白名单";
/* Class = "NSMenuItem"; title = "About"; ObjectID = "LgB-6g-Gba"; */
"LgB-6g-Gba.title" = "关于";
/* Class = "NSMenuItem"; title = "服务器设置..."; ObjectID = "M5r-E7-44f"; */
/* Class = "NSMenuItem"; title = "Server Preferences..."; ObjectID = "M5r-E7-44f"; */
"M5r-E7-44f.title" = "服务器设置...";
/* Class = "NSMenuItem"; title = "全局模式"; ObjectID = "Mw3-Jm-eXA"; */
/* Class = "NSMenuItem"; title = "Global Mode"; ObjectID = "Mw3-Jm-eXA"; */
"Mw3-Jm-eXA.title" = "全局模式";
/* Class = "NSMenuItem"; title = "扫描屏幕上的二维码..."; ObjectID = "Qe6-bF-paT"; */
/* Class = "NSMenuItem"; title = "Scan QR Code From Screen..."; ObjectID = "Qe6-bF-paT"; */
"Qe6-bF-paT.title" = "扫描屏幕上的二维码...";
/* Class = "NSMenuItem"; title = "显示当前服务器的二维码..."; ObjectID = "R6A-96-Zcb"; */
/* Class = "NSMenuItem"; title = "Show QR Code For Current Server..."; ObjectID = "R6A-96-Zcb"; */
"R6A-96-Zcb.title" = "显示当前服务器的二维码...";
/* Class = "NSMenuItem"; title = "从 GFW List 更新PAC"; ObjectID = "TFc-Ec-duM"; */
"TFc-Ec-duM.title" = "从 GFW List 更新PAC";
/* Class = "NSMenuItem"; title = "White List Mode"; ObjectID = "RvZ-Zn-29U"; */
"RvZ-Zn-29U.title" = "白名单模式";
/* Class = "NSMenuItem"; title = "反馈"; ObjectID = "W7u-7g-Gv4"; */
/* Class = "NSMenuItem"; title = "Import Bunch Json File..."; ObjectID = "T9g-gy-gvv"; */
"T9g-gy-gvv.title" = "导入服务器配置文件...";
/* Class = "NSMenuItem"; title = "Update PAC from GFW List"; ObjectID = "TFc-Ec-duM"; */
"TFc-Ec-duM.title" = "从 GFW List 更新 PAC";
/* Class = "NSMenuItem"; title = "Feedback"; ObjectID = "W7u-7g-Gv4"; */
"W7u-7g-Gv4.title" = "反馈";
/* Class = "NSMenu"; title = "代理"; ObjectID = "YZp-bf-L40"; */
/* Class = "NSMenuItem"; title = "White List IP"; ObjectID = "Xbu-Kq-BSR"; */
"Xbu-Kq-BSR.title" = "IP白名单";
/* Class = "NSMenu"; title = "Proxy"; ObjectID = "YZp-bf-L40"; */
"YZp-bf-L40.title" = "代理";
/* Class = "NSMenuItem"; title = "高级设置..."; ObjectID = "bZ3-fy-34d"; */
/* Class = "NSMenuItem"; title = "Advance Preference ..."; ObjectID = "bZ3-fy-34d"; */
"bZ3-fy-34d.title" = "高级设置...";
/* Class = "NSMenuItem"; title = "代理"; ObjectID = "diI-fB-Rss"; */
/* Class = "NSMenuItem"; title = "Proxy"; ObjectID = "diI-fB-Rss"; */
"diI-fB-Rss.title" = "代理";
/* Class = "NSMenuItem"; title = "登录时自动启动"; ObjectID = "eUq-p7-ICK"; */
/* Class = "NSMenuItem"; title = "Launch At Login"; ObjectID = "eUq-p7-ICK"; */
"eUq-p7-ICK.title" = "登录时自动启动";
/* Class = "NSMenuItem"; title = "Showsocks: On"; ObjectID = "fzk-mE-CEV"; */
"fzk-mE-CEV.title" = "Showsocks: On";
/* Class = "NSMenuItem"; title = "PAC自动模式"; ObjectID = "r07-Gu-aEz"; */
"r07-Gu-aEz.title" = "PAC自动模式";
/* Class = "NSMenuItem"; title = "Update All Wihte List"; ObjectID = "gde-ZE-086"; */
"gde-ZE-086.title" = "更新全部白名单";
/* Class = "NSMenuItem"; title = "编辑PAC用户自定规则..."; ObjectID = "rms-p0-CvB"; */
"rms-p0-CvB.title" = "编辑PAC用户自定规则...";
/* Class = "NSMenuItem"; title = "高级设置..."; ObjectID = "sbx-yz-3lO"; */
"sbx-yz-3lO.title" = "高级设置...";
/* Class = "NSMenuItem"; title = "服务器"; ObjectID = "u5M-hQ-VSc"; */
"u5M-hQ-VSc.title" = "服务器";
/* Class = "NSMenuItem"; title = "退出"; ObjectID = "vJS-JW-byz"; */
"vJS-JW-byz.title" = "退出";
/* Class = "NSMenuItem"; title = "域名白名单"; ObjectID = "L27-aH-Wwl"; */
"L27-aH-Wwl.title" = "域名白名单";
/* Class = "NSMenuItem"; title = "IP白名单"; ObjectID = "Xbu-Kq-BSR"; */
"Xbu-Kq-BSR.title" = "IP白名单";
/* Class = "NSMenuItem"; title = "白名单模式"; ObjectID = "nAe-c2-Q79"; */
/* Class = "NSMenu"; title = "White List Mode"; ObjectID = "nAe-c2-Q79"; */
"nAe-c2-Q79.title" = "白名单模式";
/* Class = "NSMenuItem"; title = "白名单模式"; ObjectID = "RvZ-Zn-29U"; */
"RvZ-Zn-29U.title" = "白名单模式";
/* Class = "NSMenuItem"; title = "Show Bunch Json Example File..."; ObjectID = "pdy-JE-50Q"; */
"pdy-JE-50Q.title" = "显示示例服务器配置文件...";
/* Class = "NSMenuItem"; title = "更新全部白名单"; ObjectID = "gde-ZE-086"; */
"gde-ZE-086.title" = "更新全部白名单";
/* Class = "NSMenuItem"; title = "Auto Mode By PAC"; ObjectID = "r07-Gu-aEz"; */
"r07-Gu-aEz.title" = "PAC自动模式";
/* Class = "NSMenuItem"; title = "Edit User Rules For PAC..."; ObjectID = "rms-p0-CvB"; */
"rms-p0-CvB.title" = "编辑PAC用户自定规则...";
/* Class = "NSMenuItem"; title = "Advance Proxy Preference..."; ObjectID = "sbx-yz-3lO"; */
"sbx-yz-3lO.title" = "高级设置...";
/* Class = "NSMenuItem"; title = "Servers"; ObjectID = "u5M-hQ-VSc"; */
"u5M-hQ-VSc.title" = "服务器";
/* Class = "NSMenuItem"; title = "Quit"; ObjectID = "vJS-JW-byz"; */
"vJS-JW-byz.title" = "退出";