├── .gitignore ├── ExternalConfig.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── ExternalConfig ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ └── transfer.png │ └── Contents.json ├── Base.lproj │ └── Main.storyboard ├── CocoaPython.swift ├── ExternalConfig.entitlements ├── Info.plist ├── ViewController.swift └── script │ ├── RSS.py │ ├── __pycache__ │ └── ssr_decode.cpython-37.pyc │ ├── ssr_decode.py │ └── v2json.py ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | 70 | # Created by .ignore support plugin (hsz.mobi) 71 | ### Python template 72 | # Byte-compiled / optimized / DLL files 73 | ExternalConfig/script/__pycache__/* 74 | ExternalConfig/script/*.py[cod] 75 | ExternalConfig/script/*$py.class 76 | 77 | # C extensions 78 | *.so 79 | 80 | # Distribution / packaging 81 | .Python 82 | env/ 83 | build/ 84 | develop-eggs/ 85 | dist/ 86 | downloads/ 87 | eggs/ 88 | .eggs/ 89 | lib/ 90 | lib64/ 91 | parts/ 92 | sdist/ 93 | var/ 94 | *.egg-info/ 95 | .installed.cfg 96 | *.egg 97 | 98 | # PyInstaller 99 | # Usually these files are written by a python script from a template 100 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 101 | *.manifest 102 | *.spec 103 | 104 | # Installer logs 105 | pip-log.txt 106 | pip-delete-this-directory.txt 107 | 108 | # Unit test / coverage reports 109 | htmlcov/ 110 | .tox/ 111 | .coverage 112 | .coverage.* 113 | .cache 114 | nosetests.xml 115 | coverage.xml 116 | *,cover 117 | .hypothesis/ 118 | 119 | # Translations 120 | *.mo 121 | *.pot 122 | 123 | # Django stuff: 124 | *.log 125 | local_settings.py 126 | 127 | # Flask stuff: 128 | instance/ 129 | .webassets-cache 130 | 131 | # Scrapy stuff: 132 | .scrapy 133 | 134 | # Sphinx documentation 135 | docs/_build/ 136 | 137 | # PyBuilder 138 | target/ 139 | 140 | # IPython Notebook 141 | .ipynb_checkpoints 142 | 143 | # pyenv 144 | .python-version 145 | 146 | # celery beat schedule file 147 | celerybeat-schedule 148 | 149 | # dotenv 150 | .env 151 | 152 | # virtualenv 153 | venv/ 154 | ENV/ 155 | 156 | # Spyder project settings 157 | .spyderproject 158 | 159 | # Rope project settings 160 | .ropeproject 161 | ### VirtualEnv template 162 | # Virtualenv 163 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 164 | .Python 165 | [Bb]in 166 | [Ii]nclude 167 | [Ll]ib 168 | [Ll]ib64 169 | [Ll]ocal 170 | [Ss]cripts 171 | pyvenv.cfg 172 | .venv 173 | pip-selfcheck.json 174 | ### JetBrains template 175 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 176 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 177 | 178 | # User-specific stuff: 179 | ExternalConfig/script/.idea/workspace.xml 180 | ExternalConfig/script/.idea/tasks.xml 181 | ExternalConfig/script/.idea/dictionaries 182 | ExternalConfig/script/.idea/vcs.xml 183 | ExternalConfig/script/.idea/jsLibraryMappings.xml 184 | 185 | # Sensitive or high-churn files: 186 | ExternalConfig/script/.idea/dataSources.ids 187 | ExternalConfig/script/.idea/dataSources.xml 188 | ExternalConfig/script/.idea/dataSources.local.xml 189 | ExternalConfig/script/.idea/sqlDataSources.xml 190 | ExternalConfig/script/.idea/dynamic.xml 191 | ExternalConfig/script/.idea/uiDesigner.xml 192 | 193 | # Gradle: 194 | ExternalConfig/script/.idea/gradle.xml 195 | ExternalConfig/script/.idea/libraries 196 | 197 | # Mongo Explorer plugin: 198 | ExternalConfig/script/.idea/mongoSettings.xml 199 | 200 | ExternalConfig/script/.idea/ 201 | 202 | ## File-based project format: 203 | *.iws 204 | 205 | ## Plugin-specific files: 206 | 207 | # IntelliJ 208 | /out/ 209 | 210 | # mpeltonen/sbt-idea plugin 211 | ./ExternalConfig/script/.idea_modules/ 212 | 213 | # JIRA plugin 214 | atlassian-ide-plugin.xml 215 | 216 | # Crashlytics plugin (for Android Studio and IntelliJ) 217 | com_crashlytics_export_strings.xml 218 | crashlytics.properties 219 | crashlytics-build.properties 220 | fabric.properties 221 | 222 | -------------------------------------------------------------------------------- /ExternalConfig.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4E3B00CE22FAC83300F89788 /* CocoaPython.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3B00CD22FAC83300F89788 /* CocoaPython.swift */; }; 11 | 4E3B00D122FACF2500F89788 /* ssr_decode.py in Resources */ = {isa = PBXBuildFile; fileRef = 4E3B00CF22FACF2500F89788 /* ssr_decode.py */; }; 12 | 4E3B00D222FACF2500F89788 /* RSS.py in Resources */ = {isa = PBXBuildFile; fileRef = 4E3B00D022FACF2500F89788 /* RSS.py */; }; 13 | 4E7544942317D45700A699DD /* v2json.py in Resources */ = {isa = PBXBuildFile; fileRef = 4E7544932317D45700A699DD /* v2json.py */; }; 14 | 4EC35B7522F9651D00EF295F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC35B7422F9651D00EF295F /* AppDelegate.swift */; }; 15 | 4EC35B7722F9651D00EF295F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC35B7622F9651D00EF295F /* ViewController.swift */; }; 16 | 4EC35B7922F9651E00EF295F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4EC35B7822F9651E00EF295F /* Assets.xcassets */; }; 17 | 4EC35B7C22F9651E00EF295F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4EC35B7A22F9651E00EF295F /* Main.storyboard */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | 4E3B00EB22FBD27200F89788 /* Embed Frameworks */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = ""; 25 | dstSubfolderSpec = 10; 26 | files = ( 27 | ); 28 | name = "Embed Frameworks"; 29 | runOnlyForDeploymentPostprocessing = 0; 30 | }; 31 | /* End PBXCopyFilesBuildPhase section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 4E3B00CD22FAC83300F89788 /* CocoaPython.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CocoaPython.swift; sourceTree = ""; }; 35 | 4E3B00CF22FACF2500F89788 /* ssr_decode.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = ssr_decode.py; sourceTree = ""; }; 36 | 4E3B00D022FACF2500F89788 /* RSS.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = RSS.py; sourceTree = ""; }; 37 | 4E7544932317D45700A699DD /* v2json.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = v2json.py; sourceTree = ""; }; 38 | 4EC35B7122F9651D00EF295F /* ExternalConfig.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExternalConfig.app; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 4EC35B7422F9651D00EF295F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 40 | 4EC35B7622F9651D00EF295F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 41 | 4EC35B7822F9651E00EF295F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 42 | 4EC35B7B22F9651E00EF295F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | 4EC35B7D22F9651E00EF295F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 44 | 4EC35B7E22F9651E00EF295F /* ExternalConfig.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ExternalConfig.entitlements; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 4EC35B6E22F9651D00EF295F /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 4E3B00CA22FAB1E100F89788 /* script */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 4E7544932317D45700A699DD /* v2json.py */, 62 | 4E3B00D022FACF2500F89788 /* RSS.py */, 63 | 4E3B00CF22FACF2500F89788 /* ssr_decode.py */, 64 | ); 65 | path = script; 66 | sourceTree = ""; 67 | }; 68 | 4EC35B6822F9651D00EF295F = { 69 | isa = PBXGroup; 70 | children = ( 71 | 4EC35B7322F9651D00EF295F /* ExternalConfig */, 72 | 4EC35B7222F9651D00EF295F /* Products */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | 4EC35B7222F9651D00EF295F /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 4EC35B7122F9651D00EF295F /* ExternalConfig.app */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | 4EC35B7322F9651D00EF295F /* ExternalConfig */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 4E3B00CA22FAB1E100F89788 /* script */, 88 | 4EC35B7422F9651D00EF295F /* AppDelegate.swift */, 89 | 4EC35B7622F9651D00EF295F /* ViewController.swift */, 90 | 4E3B00CD22FAC83300F89788 /* CocoaPython.swift */, 91 | 4EC35B7822F9651E00EF295F /* Assets.xcassets */, 92 | 4EC35B7A22F9651E00EF295F /* Main.storyboard */, 93 | 4EC35B7D22F9651E00EF295F /* Info.plist */, 94 | 4EC35B7E22F9651E00EF295F /* ExternalConfig.entitlements */, 95 | ); 96 | path = ExternalConfig; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | 4EC35B7022F9651D00EF295F /* ExternalConfig */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = 4EC35B8122F9651E00EF295F /* Build configuration list for PBXNativeTarget "ExternalConfig" */; 105 | buildPhases = ( 106 | 4EC35B6D22F9651D00EF295F /* Sources */, 107 | 4EC35B6E22F9651D00EF295F /* Frameworks */, 108 | 4EC35B6F22F9651D00EF295F /* Resources */, 109 | 4E3B00EB22FBD27200F89788 /* Embed Frameworks */, 110 | ); 111 | buildRules = ( 112 | ); 113 | dependencies = ( 114 | ); 115 | name = ExternalConfig; 116 | productName = ExternalConfig; 117 | productReference = 4EC35B7122F9651D00EF295F /* ExternalConfig.app */; 118 | productType = "com.apple.product-type.application"; 119 | }; 120 | /* End PBXNativeTarget section */ 121 | 122 | /* Begin PBXProject section */ 123 | 4EC35B6922F9651D00EF295F /* Project object */ = { 124 | isa = PBXProject; 125 | attributes = { 126 | LastSwiftUpdateCheck = 1030; 127 | LastUpgradeCheck = 1030; 128 | ORGANIZATIONNAME = OnePiece; 129 | TargetAttributes = { 130 | 4EC35B7022F9651D00EF295F = { 131 | CreatedOnToolsVersion = 10.3; 132 | SystemCapabilities = { 133 | com.apple.Sandbox = { 134 | enabled = 0; 135 | }; 136 | }; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = 4EC35B6C22F9651D00EF295F /* Build configuration list for PBXProject "ExternalConfig" */; 141 | compatibilityVersion = "Xcode 9.3"; 142 | developmentRegion = en; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | Base, 147 | ); 148 | mainGroup = 4EC35B6822F9651D00EF295F; 149 | productRefGroup = 4EC35B7222F9651D00EF295F /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | 4EC35B7022F9651D00EF295F /* ExternalConfig */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | 4EC35B6F22F9651D00EF295F /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | 4E3B00D122FACF2500F89788 /* ssr_decode.py in Resources */, 164 | 4E3B00D222FACF2500F89788 /* RSS.py in Resources */, 165 | 4EC35B7922F9651E00EF295F /* Assets.xcassets in Resources */, 166 | 4EC35B7C22F9651E00EF295F /* Main.storyboard in Resources */, 167 | 4E7544942317D45700A699DD /* v2json.py in Resources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXResourcesBuildPhase section */ 172 | 173 | /* Begin PBXSourcesBuildPhase section */ 174 | 4EC35B6D22F9651D00EF295F /* Sources */ = { 175 | isa = PBXSourcesBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | 4EC35B7722F9651D00EF295F /* ViewController.swift in Sources */, 179 | 4EC35B7522F9651D00EF295F /* AppDelegate.swift in Sources */, 180 | 4E3B00CE22FAC83300F89788 /* CocoaPython.swift in Sources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXSourcesBuildPhase section */ 185 | 186 | /* Begin PBXVariantGroup section */ 187 | 4EC35B7A22F9651E00EF295F /* Main.storyboard */ = { 188 | isa = PBXVariantGroup; 189 | children = ( 190 | 4EC35B7B22F9651E00EF295F /* Base */, 191 | ); 192 | name = Main.storyboard; 193 | sourceTree = ""; 194 | }; 195 | /* End PBXVariantGroup section */ 196 | 197 | /* Begin XCBuildConfiguration section */ 198 | 4EC35B7F22F9651E00EF295F /* Debug */ = { 199 | isa = XCBuildConfiguration; 200 | buildSettings = { 201 | ALWAYS_SEARCH_USER_PATHS = NO; 202 | CLANG_ANALYZER_NONNULL = YES; 203 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_ENABLE_OBJC_WEAK = YES; 209 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 210 | CLANG_WARN_BOOL_CONVERSION = YES; 211 | CLANG_WARN_COMMA = YES; 212 | CLANG_WARN_CONSTANT_CONVERSION = YES; 213 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 214 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 215 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 216 | CLANG_WARN_EMPTY_BODY = YES; 217 | CLANG_WARN_ENUM_CONVERSION = YES; 218 | CLANG_WARN_INFINITE_RECURSION = YES; 219 | CLANG_WARN_INT_CONVERSION = YES; 220 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 221 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 222 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 223 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 224 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 225 | CLANG_WARN_STRICT_PROTOTYPES = YES; 226 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 227 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 228 | CLANG_WARN_UNREACHABLE_CODE = YES; 229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 230 | CODE_SIGN_IDENTITY = "-"; 231 | COPY_PHASE_STRIP = NO; 232 | DEBUG_INFORMATION_FORMAT = dwarf; 233 | ENABLE_STRICT_OBJC_MSGSEND = YES; 234 | ENABLE_TESTABILITY = YES; 235 | GCC_C_LANGUAGE_STANDARD = gnu11; 236 | GCC_DYNAMIC_NO_PIC = NO; 237 | GCC_NO_COMMON_BLOCKS = YES; 238 | GCC_OPTIMIZATION_LEVEL = 0; 239 | GCC_PREPROCESSOR_DEFINITIONS = ( 240 | "DEBUG=1", 241 | "$(inherited)", 242 | ); 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_UNDECLARED_SELECTOR = YES; 246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 247 | GCC_WARN_UNUSED_FUNCTION = YES; 248 | GCC_WARN_UNUSED_VARIABLE = YES; 249 | MACOSX_DEPLOYMENT_TARGET = 10.14; 250 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 251 | MTL_FAST_MATH = YES; 252 | ONLY_ACTIVE_ARCH = YES; 253 | SDKROOT = macosx; 254 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 255 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 256 | }; 257 | name = Debug; 258 | }; 259 | 4EC35B8022F9651E00EF295F /* Release */ = { 260 | isa = XCBuildConfiguration; 261 | buildSettings = { 262 | ALWAYS_SEARCH_USER_PATHS = NO; 263 | CLANG_ANALYZER_NONNULL = YES; 264 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 266 | CLANG_CXX_LIBRARY = "libc++"; 267 | CLANG_ENABLE_MODULES = YES; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | CLANG_ENABLE_OBJC_WEAK = YES; 270 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_COMMA = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 275 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 276 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_INFINITE_RECURSION = YES; 280 | CLANG_WARN_INT_CONVERSION = YES; 281 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 282 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 283 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 286 | CLANG_WARN_STRICT_PROTOTYPES = YES; 287 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 288 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | CODE_SIGN_IDENTITY = "-"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 294 | ENABLE_NS_ASSERTIONS = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu11; 297 | GCC_NO_COMMON_BLOCKS = YES; 298 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 299 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 300 | GCC_WARN_UNDECLARED_SELECTOR = YES; 301 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 302 | GCC_WARN_UNUSED_FUNCTION = YES; 303 | GCC_WARN_UNUSED_VARIABLE = YES; 304 | MACOSX_DEPLOYMENT_TARGET = 10.14; 305 | MTL_ENABLE_DEBUG_INFO = NO; 306 | MTL_FAST_MATH = YES; 307 | SDKROOT = macosx; 308 | SWIFT_COMPILATION_MODE = wholemodule; 309 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 310 | }; 311 | name = Release; 312 | }; 313 | 4EC35B8222F9651E00EF295F /* Debug */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 317 | CODE_SIGN_ENTITLEMENTS = ExternalConfig/ExternalConfig.entitlements; 318 | CODE_SIGN_IDENTITY = "Mac Developer"; 319 | CODE_SIGN_STYLE = Automatic; 320 | COMBINE_HIDPI_IMAGES = YES; 321 | DEVELOPMENT_TEAM = C7Y628K2L4; 322 | ENABLE_HARDENED_RUNTIME = YES; 323 | FRAMEWORK_SEARCH_PATHS = ( 324 | "$(inherited)", 325 | "$(PROJECT_DIR)/ExternalConfig", 326 | ); 327 | INFOPLIST_FILE = ExternalConfig/Info.plist; 328 | LD_RUNPATH_SEARCH_PATHS = ( 329 | "$(inherited)", 330 | "@executable_path/../Frameworks", 331 | ); 332 | LIBRARY_SEARCH_PATHS = ( 333 | "$(inherited)", 334 | "$(PROJECT_DIR)/ExternalConfig", 335 | "$(PROJECT_DIR)/ExternalConfig/lib/python3.7/config-3.7m-darwin", 336 | "$(PROJECT_DIR)/ExternalConfig/lib", 337 | ); 338 | MACOSX_DEPLOYMENT_TARGET = 10.12; 339 | PRODUCT_BUNDLE_IDENTIFIER = com.OnePiece.ExternalConfig; 340 | PRODUCT_NAME = "$(TARGET_NAME)"; 341 | PROVISIONING_PROFILE_SPECIFIER = ""; 342 | SWIFT_VERSION = 5.0; 343 | }; 344 | name = Debug; 345 | }; 346 | 4EC35B8322F9651E00EF295F /* Release */ = { 347 | isa = XCBuildConfiguration; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | CODE_SIGN_ENTITLEMENTS = ExternalConfig/ExternalConfig.entitlements; 351 | CODE_SIGN_IDENTITY = "Mac Developer"; 352 | CODE_SIGN_STYLE = Automatic; 353 | COMBINE_HIDPI_IMAGES = YES; 354 | DEVELOPMENT_TEAM = C7Y628K2L4; 355 | ENABLE_HARDENED_RUNTIME = YES; 356 | FRAMEWORK_SEARCH_PATHS = ( 357 | "$(inherited)", 358 | "$(PROJECT_DIR)/ExternalConfig", 359 | ); 360 | INFOPLIST_FILE = ExternalConfig/Info.plist; 361 | LD_RUNPATH_SEARCH_PATHS = ( 362 | "$(inherited)", 363 | "@executable_path/../Frameworks", 364 | ); 365 | LIBRARY_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "$(PROJECT_DIR)/ExternalConfig", 368 | "$(PROJECT_DIR)/ExternalConfig/lib/python3.7/config-3.7m-darwin", 369 | "$(PROJECT_DIR)/ExternalConfig/lib", 370 | ); 371 | MACOSX_DEPLOYMENT_TARGET = 10.12; 372 | PRODUCT_BUNDLE_IDENTIFIER = com.OnePiece.ExternalConfig; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | PROVISIONING_PROFILE_SPECIFIER = ""; 375 | SWIFT_VERSION = 5.0; 376 | }; 377 | name = Release; 378 | }; 379 | /* End XCBuildConfiguration section */ 380 | 381 | /* Begin XCConfigurationList section */ 382 | 4EC35B6C22F9651D00EF295F /* Build configuration list for PBXProject "ExternalConfig" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | 4EC35B7F22F9651E00EF295F /* Debug */, 386 | 4EC35B8022F9651E00EF295F /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | 4EC35B8122F9651E00EF295F /* Build configuration list for PBXNativeTarget "ExternalConfig" */ = { 392 | isa = XCConfigurationList; 393 | buildConfigurations = ( 394 | 4EC35B8222F9651E00EF295F /* Debug */, 395 | 4EC35B8322F9651E00EF295F /* Release */, 396 | ); 397 | defaultConfigurationIsVisible = 0; 398 | defaultConfigurationName = Release; 399 | }; 400 | /* End XCConfigurationList section */ 401 | }; 402 | rootObject = 4EC35B6922F9651D00EF295F /* Project object */; 403 | } 404 | -------------------------------------------------------------------------------- /ExternalConfig.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExternalConfig.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ExternalConfig/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ExternalConfig 4 | // 5 | // Created by asd on 6/8/2019. 6 | // Copyright © 2019 OnePiece. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | func applicationDidFinishLaunching(_ aNotification: Notification) { 15 | // Insert code here to initialize your application 16 | } 17 | 18 | func applicationWillTerminate(_ aNotification: Notification) { 19 | // Insert code here to tear down your application 20 | } 21 | 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /ExternalConfig/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "512x512", 45 | "idiom" : "mac", 46 | "filename" : "transfer.png", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "idiom" : "mac", 51 | "size" : "512x512", 52 | "scale" : "2x" 53 | } 54 | ], 55 | "info" : { 56 | "version" : 1, 57 | "author" : "xcode" 58 | } 59 | } -------------------------------------------------------------------------------- /ExternalConfig/Assets.xcassets/AppIcon.appiconset/transfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhoJave/ExternalConfig/d33e151949eb7b83d404f9d997681a084034eb5c/ExternalConfig/Assets.xcassets/AppIcon.appiconset/transfer.png -------------------------------------------------------------------------------- /ExternalConfig/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ExternalConfig/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | Default 531 | 532 | 533 | 534 | 535 | 536 | 537 | Left to Right 538 | 539 | 540 | 541 | 542 | 543 | 544 | Right to Left 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | Default 556 | 557 | 558 | 559 | 560 | 561 | 562 | Left to Right 563 | 564 | 565 | 566 | 567 | 568 | 569 | Right to Left 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 756 | 757 | 758 | 759 | 760 | 761 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | -------------------------------------------------------------------------------- /ExternalConfig/CocoaPython.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CocoaPython.swift 3 | // json2Swift 4 | // 5 | // Created by Shi Jian on 2017/11/9. 6 | // Copyright © 2017年 HHMedic. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | public typealias completeBlock = ((_ results: [String], _ errors: String?)->Void) 12 | 13 | public class CocoaPython { 14 | 15 | //NSTask has been renamed to Process 16 | let buildTask = Process() 17 | let outPip = Pipe() 18 | let errorPipe = Pipe() 19 | /// 完成回调 20 | var completed: completeBlock? 21 | 22 | /// 是否异步执行回调,只在runAsync下生效 23 | var asyncComlete = false 24 | 25 | /// 多个返回结果的分隔符 26 | public var splitPara: Character? 27 | 28 | public init(scrPath: String, args: [String]? = nil, complete: completeBlock? = nil) { 29 | completed = complete 30 | 31 | buildTask.launchPath = "/usr/local/bin/python3" 32 | 33 | var allArgs = [String]() 34 | allArgs.append(scrPath) 35 | if let aArg = args { 36 | allArgs.append(contentsOf: aArg) 37 | } 38 | buildTask.arguments = allArgs 39 | 40 | buildTask.standardInput = Pipe() 41 | buildTask.standardOutput = outPip 42 | buildTask.standardError = errorPipe 43 | 44 | } 45 | 46 | /// 同步执行 47 | public func runSync() { 48 | buildTask.launch() 49 | print(buildTask.arguments!) 50 | buildTask.waitUntilExit() 51 | 52 | // 错误处理 53 | if let aError = fetchResult(errorPipe), aError != "" { 54 | runComlete(["-1"], aError) 55 | return 56 | } 57 | runComlete(processResult(), nil) 58 | } 59 | 60 | /// 异步执行 61 | /// 62 | /// - Parameter asyncComlete: 回调是否异步主线程执行 63 | public func runAsync(asyncComlete: Bool = true) { 64 | self.asyncComlete = asyncComlete 65 | DispatchQueue.global().async { 66 | self.runSync() 67 | } 68 | } 69 | } 70 | 71 | extension CocoaPython { 72 | 73 | /// 执行block回调 74 | fileprivate func runComlete(_ result: [String], _ error: String?) { 75 | if asyncComlete { 76 | asyncComlete = false 77 | DispatchQueue.main.async { 78 | self.completed?(result, error) 79 | } 80 | } else { 81 | completed?(result, error) 82 | } 83 | } 84 | 85 | // 获取返回数据的字符串形式 86 | fileprivate func fetchResult(_ pipe: Pipe) -> String? { 87 | let data = pipe.fileHandleForReading.readDataToEndOfFile() 88 | return String(data: data, encoding: String.Encoding.utf8) 89 | } 90 | 91 | fileprivate func processResult() -> [String] { 92 | let result = fetchResult(outPip) ?? "" 93 | guard let splt = splitPara else { return [result] } 94 | return result.split(separator: splt).map(String.init) 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /ExternalConfig/ExternalConfig.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.temporary-exception.files.home-relative-path.read-write 6 | 7 | ~ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ExternalConfig/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 2.0 21 | CFBundleVersion 22 | 2 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2019 OnePiece. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /ExternalConfig/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ExternalConfig 4 | // 5 | // Created by asd on 6/8/2019. 6 | // Copyright © 2019 OnePiece. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ViewController: NSViewController,NSUserNotificationCenterDelegate { 12 | 13 | let dataSource = ["SSR订阅","V2RAY订阅"] 14 | @IBOutlet weak var portNum: NSTextField! 15 | @IBOutlet weak var subType: NSComboBox! 16 | @IBOutlet weak var subScribeURL: NSTextField! 17 | @IBOutlet var resutView: NSTextView! 18 | @IBOutlet weak var execButton: NSButton! 19 | @IBAction func runSSR2JSON(_ sender: NSButton) { 20 | subScribeURL.resignFirstResponder() 21 | portNum.resignFirstResponder() 22 | resutView.string = "处理中请稍后..." 23 | execButton.isEnabled = false 24 | runScript() 25 | } 26 | 27 | @IBAction func copy(_ sender: NSButton) { 28 | let pasteBoard = NSPasteboard.general 29 | pasteBoard.declareTypes([NSPasteboard.PasteboardType.init("NSStringPboardType")], owner: nil) 30 | if resutView.string.count == 0 { 31 | //没有可复制的内容 32 | print("没有可复制的内容") 33 | }else{ 34 | let copySuccess = pasteBoard.setString(resutView.string, forType: NSPasteboard.PasteboardType.init("NSStringPboardType")) 35 | if copySuccess { 36 | showNotification(content: "") 37 | } 38 | } 39 | 40 | 41 | } 42 | 43 | func showNotification(content: String){ 44 | let notice = NSUserNotification.init() 45 | notice.title = "复制External配置到剪切板" 46 | notice.subtitle = "复制成功" 47 | 48 | let center = NSUserNotificationCenter.default 49 | center.delegate = self 50 | center.scheduleNotification(notice) 51 | } 52 | 53 | func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool { 54 | return true 55 | } 56 | 57 | override func viewDidLoad() { 58 | super.viewDidLoad() 59 | resutView.isEditable = false 60 | // Do any additional setup after loading the view. 61 | subType.usesDataSource = true 62 | subType.dataSource = self 63 | subType.delegate = self 64 | } 65 | 66 | func runScript() { 67 | guard let aPath = Bundle.main.path(forResource: subType.stringValue == self.dataSource[0] ? "RSS" :"v2json", ofType: "py") else { return } 68 | 69 | let script = CocoaPython(scrPath: aPath, args: fetchArgs()) { [weak self] in 70 | self?.scriptFinish(results: $0, error: $1) 71 | } 72 | 73 | script.runAsync() 74 | } 75 | 76 | func fetchArgs() -> [String] { 77 | let args = ["-s \(subScribeURL.stringValue)","-p \(portNum.intValue)"] 78 | return args 79 | } 80 | 81 | // 执行完成的回调 82 | func scriptFinish(results: [String], error: String?) { 83 | if let aError = error { 84 | resutView.string = "解析错误\r\n" + aError 85 | execButton.isEnabled = true 86 | return 87 | } 88 | resutView.string = results[0] 89 | execButton.isEnabled = true 90 | } 91 | 92 | override var representedObject: Any? { 93 | didSet { 94 | // Update the view, if already loaded. 95 | } 96 | } 97 | 98 | 99 | } 100 | 101 | extension ViewController: NSComboBoxDelegate,NSComboBoxDataSource { 102 | //MARK: dataSource 103 | func numberOfItems(in comboBox: NSComboBox) -> Int { 104 | return dataSource.count 105 | } 106 | 107 | func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? { 108 | return dataSource[index] 109 | } 110 | 111 | //MARK: delegate 112 | func comboBoxSelectionDidChange(_ notification: Notification) { 113 | let combox = notification.object as! NSComboBox 114 | let selIndex = combox.indexOfSelectedItem 115 | // print("comboBoxSelectionDidChange select item\(self.dataSource[selIndex])") 116 | subType.stringValue = self.dataSource[selIndex] 117 | // print(subType.stringValue) 118 | if subType.stringValue == self.dataSource[0] { 119 | self.portNum.stringValue = "19522" 120 | }else{ 121 | self.portNum.stringValue = "19829" 122 | } 123 | subScribeURL.stringValue = "" 124 | portNum.resignFirstResponder() 125 | } 126 | 127 | func comboBoxSelectionIsChanging(_ notification: Notification) { 128 | let combox = notification.object as! NSComboBox 129 | let selIndex = combox.indexOfSelectedItem 130 | // print("comboBoxSelectionIsChanging select item\(self.dataSource[selIndex])") 131 | subType.stringValue = self.dataSource[selIndex] 132 | subScribeURL.stringValue = "" 133 | portNum.resignFirstResponder() 134 | 135 | // print(subType.stringValue) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /ExternalConfig/script/RSS.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import ssr_decode 4 | import argparse 5 | import os 6 | import json 7 | import socket 8 | from os.path import expanduser 9 | import re 10 | from urllib import request 11 | 12 | url = "" 13 | # default port 14 | port = 19522 15 | home = expanduser("~") 16 | surgePath = "/Documents/Surge/config" 17 | 18 | 19 | def get_data(url): 20 | header = { 21 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'} 22 | req = request.Request(url, headers=header) 23 | with request.urlopen(req) as res: 24 | data = str(res.read(), encoding="utf-8") 25 | return data 26 | 27 | 28 | # 解码订阅内容获得配置保存在目录config 29 | 30 | def del_files(path): 31 | for root, dirs, files in os.walk(path): 32 | for name in files: 33 | if name.endswith(".json"): 34 | os.remove(os.path.join(root, name)) 35 | 36 | 37 | def save_config(url, port): 38 | data = get_data(url) 39 | ssr_str = ssr_decode.decode(data) 40 | 41 | code_list = re.findall(r"ssr://(\w+)", ssr_str) 42 | 43 | if not os.path.exists(home + surgePath + '/SSRJson'): 44 | os.makedirs(home + surgePath + '/SSRJson') 45 | writepath = home + surgePath + '/external.txt' 46 | mode = 'a' if os.path.exists(writepath) else 'w' 47 | f = open(writepath, mode) 48 | f.truncate() 49 | f.close() 50 | for code in code_list: 51 | index = code_list.index(code) 52 | try: 53 | # print(code,index,port) #pass port 54 | ssr_decode.save_as_json(code, port, name=str(index)) 55 | except UnicodeDecodeError: 56 | print(ssr_decode.decode(code)) # 打印有误的链接 57 | 58 | 59 | def getIP(domain): 60 | try: 61 | myaddr = socket.gethostbyname(domain) 62 | except BaseException: 63 | myaddr = 'unknown' 64 | return myaddr 65 | 66 | 67 | def configToExternal(): 68 | rootdir = home + surgePath 69 | f = open(home + surgePath + '/external.txt', 'w+') 70 | f.truncate() 71 | f.close() 72 | for root, dirs, files in os.walk(rootdir + '/SSRJson'): # 当前路径、子文件夹名称、文件列表 73 | for filename in files: 74 | if filename.endswith(".json"): 75 | fn = filename.replace('.json','') 76 | # print(fn) 77 | with open(rootdir + '/SSRJson' + '/' + filename, 'r') as f: 78 | tmp = json.loads(f.read()) 79 | lp = tmp['local_port'] 80 | se = tmp['server'] 81 | serverIP = getIP(se) 82 | # print(lp) 83 | print(fn + ' = external, exec = \"' + home + surgePath + '/ss-local\", args = \"-c\", args = \"' + rootdir + '/SSRJson' + '/' + filename + '\",' + 'local-port = ' + str(lp) + ', addresses = ' + serverIP) 84 | f = open(rootdir + '/external.txt', 'a') 85 | f.write(fn + ' = external, exec = \"' + home + surgePath + '/ss-local\", args = \"-c\", args = \"' + rootdir + '/SSRJson' + '/' + filename + '\",' + 'local-port = ' + str(lp) + ', addresses = ' + serverIP + '\n') 86 | f.close() 87 | nodeListStr = '' 88 | for filename in files: 89 | if filename.endswith(".json"): 90 | fn = filename.replace('.json','') 91 | nodeListStr = (nodeListStr + fn + ',') 92 | print(nodeListStr) 93 | f = open(rootdir + '/external.txt', 'a') 94 | f.write(nodeListStr) 95 | f.close() 96 | 97 | 98 | if __name__ == '__main__': 99 | parser = argparse.ArgumentParser() 100 | parser.add_argument("-s", help="this is the ssr subscribe address") 101 | parser.add_argument("-p", help="this is the destined port number") 102 | # parser.add_argument("-p","--port",help="this is the destined port number") 103 | args = parser.parse_args() 104 | # print('________打印参数________') 105 | # print(args) 106 | if args.s: 107 | # print(8,args.s) 108 | url = args.s 109 | if args.p: 110 | port = args.p 111 | 112 | # url = input("ssr subscrible link: ") 113 | del_files(home + surgePath + '/SSRJson') 114 | save_config(url, port) 115 | configToExternal() 116 | # print("successful!") 117 | -------------------------------------------------------------------------------- /ExternalConfig/script/__pycache__/ssr_decode.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WhoJave/ExternalConfig/d33e151949eb7b83d404f9d997681a084034eb5c/ExternalConfig/script/__pycache__/ssr_decode.cpython-37.pyc -------------------------------------------------------------------------------- /ExternalConfig/script/ssr_decode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import base64 4 | import re 5 | import json 6 | import os 7 | from os.path import expanduser 8 | 9 | ssr = "ssr://" 10 | code = ssr[6:] 11 | name = 'config' 12 | surgePath = "/Documents/Surge/config" 13 | 14 | #功能:解析我们的ssr code 返回一个有config,group,remarks组成的列表, 15 | #参数:s为去掉了前缀'ssr://'的ssr链接code,类型为string 16 | #返回:[config,group,remarks],其中config,类型为dict;group和remarks,类型为string 17 | def Analyze(s,port): 18 | 19 | config = { 20 | "server": "0.0.0.0", 21 | "server_ipv6": "::", 22 | "server_port": 8388, 23 | "local_address": "127.0.0.1", 24 | "local_port": port, 25 | 26 | "password": "m", 27 | "method": "aes-128-ctr", 28 | "protocol": "auth_aes128_md5", 29 | "protocol_param": "", 30 | "obfs": "tls1.2_ticket_auth_compatible", 31 | "obfs_param": "" 32 | } 33 | 34 | s = decode(s) 35 | spilted = re.split(':', s) 36 | pass_param = spilted[5] 37 | pass_param_spilted = re.split("\/\?", pass_param) 38 | passwd = decode(pass_param_spilted[0]) 39 | 40 | #匹配param、remark和group 41 | try: 42 | obfs_param = re.search(r'obfsparam=([^&]+)', pass_param_spilted[1]).group(1) 43 | obfs_param = decode(obfs_param) 44 | except: 45 | obfs_param = '' 46 | try: 47 | protocol_param = re.search(r'protoparam=([^&]+)', pass_param_spilted[1]) 48 | protocol_param = decode(protocol_param.group(1)) 49 | except: 50 | protocol_param = '' 51 | try: 52 | remarks = re.search(r'remarks=([^&]+)', pass_param_spilted[1]).group(1) 53 | remarks = decode(remarks) 54 | except: 55 | remarks = '' 56 | try: 57 | group = re.search(r'group=([^&]+)', pass_param_spilted[1]).group(1) 58 | group = decode(group) 59 | except: 60 | group = '' 61 | 62 | config['server'] = spilted[0] 63 | config['server_port'] = int(spilted[1]) 64 | config['password'] = passwd 65 | config['method'] = spilted[3] 66 | config['protocol'] = spilted[2] 67 | config['obfs'] = spilted[4] 68 | config['protocol_param'] = protocol_param 69 | config['obfs_param'] = obfs_param 70 | 71 | return [config,group,remarks] 72 | 73 | #功能:Base64解码(针对url) 74 | #参数:待解码的字符串s,类型为string 75 | #返回:解码后的内容,类型为string 76 | def decode(s): 77 | 78 | count = len(s) 79 | num = 4-count%4 80 | if count%4==0: 81 | s = base64.urlsafe_b64decode(s) 82 | else: 83 | s = s + num*"=" 84 | s = base64.urlsafe_b64decode(s) 85 | 86 | s = str(s,encoding="utf-8") 87 | return s 88 | 89 | #功能:解析ssr并保存在config目录下 90 | #参数:d为去掉'ssr://'前缀,name为保存的config的名字默认为conf 91 | def save_as_json(d,port,name='conf'): 92 | # print(d) 93 | # print('***********') 94 | [data_dict,group,remarks] = Analyze(d,port) 95 | #修改local端口号 96 | data_dict['local_port'] = int(data_dict['local_port']) + int(name) 97 | json_str = json.dumps(data_dict) 98 | home = expanduser("~") 99 | if not os.path.exists(home + surgePath + '/SSRJson'): 100 | os.makedirs(home + surgePath + '/SSRJson') 101 | with open(home + surgePath + '/SSRJson' + '/' + remarks + '.json', 'w') as f: 102 | json.dump(data_dict, f) 103 | 104 | #从终端输入ssr链接,将解析后的配置保存到目录config下 105 | if __name__ == "__main__": 106 | ssr = input('ssr link:') 107 | code = ssr[6:] 108 | name = input('config name:') 109 | try: 110 | # print(code) 111 | # print(name) 112 | # save_as_json(code,port,name) 113 | print("Successful:please check config at \'config/\'") 114 | except: 115 | print("Error:Fail to save config!") 116 | -------------------------------------------------------------------------------- /ExternalConfig/script/v2json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import json 5 | import base64 6 | import argparse 7 | import binascii 8 | import traceback 9 | import urllib.request 10 | import urllib.parse 11 | import socket 12 | from os.path import expanduser 13 | 14 | vmscheme = "vmess://" 15 | ssscheme = "ss://" 16 | 17 | home = expanduser("~") 18 | surgePath = "/Documents/Surge/config/vmessJson" 19 | configPath = "/Documents/Surge/config" 20 | 21 | TPL = {} 22 | TPL["CLIENT"] = """ 23 | { 24 | "log": { 25 | "loglevel": "info" 26 | }, 27 | "inbound": { 28 | "listen": "127.0.0.1", 29 | "port": 11098, 30 | "protocol": "socks", 31 | "settings": { 32 | "auth": "noauth", 33 | "udp": true, 34 | "ip": "127.0.0.1" 35 | } 36 | }, 37 | "outbound": { 38 | "protocol": "vmess", 39 | "settings": { 40 | "vnext": [ 41 | { 42 | "address": "www.google.com", 43 | "port": 666, 44 | "users": [ 45 | { 46 | "id": "15sd756f-8fc6-3be5-93e3-24094d5fbb8a", 47 | "alterId": 2 48 | } 49 | ] 50 | } 51 | ] 52 | } 53 | } 54 | } 55 | """ 56 | 57 | 58 | def parseLink(link): 59 | if link.startswith(ssscheme): 60 | return parseSs(link) 61 | elif link.startswith(vmscheme): 62 | return parseVmess(link) 63 | else: 64 | print("ERROR: This script supports only vmess://(N/NG) and ss:// links") 65 | return None 66 | 67 | 68 | def parseSs(sslink): 69 | RETOBJ = { 70 | "v": "2", 71 | "ps": "", 72 | "add": "", 73 | "port": "", 74 | "id": "", 75 | "aid": "", 76 | "net": "shadowsocks", 77 | "type": "", 78 | "host": "", 79 | "path": "", 80 | "tls": "" 81 | } 82 | if sslink.startswith(ssscheme): 83 | info = sslink[len(ssscheme):] 84 | 85 | if info.rfind("#") > 0: 86 | info, _ps = info.split("#", 2) 87 | RETOBJ["ps"] = urllib.parse.unquote(_ps) 88 | 89 | if info.find("@") < 0: 90 | # old style link 91 | # paddings 92 | blen = len(info) 93 | if blen % 4 > 0: 94 | info += "=" * (4 - blen % 4) 95 | 96 | info = base64.b64decode(info).decode() 97 | 98 | atidx = info.rfind("@") 99 | method, password = info[:atidx].split(":", 2) 100 | addr, port = info[atidx + 1:].split(":", 2) 101 | else: 102 | atidx = info.rfind("@") 103 | addr, port = info[atidx + 1:].split(":", 2) 104 | 105 | info = info[:atidx] 106 | blen = len(info) 107 | if blen % 4 > 0: 108 | info += "=" * (4 - blen % 4) 109 | 110 | info = base64.b64decode(info).decode() 111 | method, password = info.split(":", 2) 112 | 113 | RETOBJ["add"] = addr 114 | RETOBJ["port"] = port 115 | RETOBJ["aid"] = method 116 | RETOBJ["id"] = password 117 | return RETOBJ 118 | 119 | 120 | def parseVmess(vmesslink): 121 | """ 122 | return: 123 | { 124 | "v": "2", 125 | "ps": "remark", 126 | "add": "4.3.2.1", 127 | "port": "1024", 128 | "id": "xxx", 129 | "aid": "64", 130 | "net": "tcp", 131 | "type": "none", 132 | "host": "", 133 | "path": "", 134 | "tls": "" 135 | } 136 | """ 137 | if vmesslink.startswith(vmscheme): 138 | bs = vmesslink[len(vmscheme):] 139 | # paddings 140 | blen = len(bs) 141 | if blen % 4 > 0: 142 | bs += "=" * (4 - blen % 4) 143 | 144 | vms = base64.b64decode(bs).decode() 145 | return json.loads(vms) 146 | else: 147 | raise Exception("vmess link invalid") 148 | 149 | 150 | def load_TPL(stype): 151 | s = TPL[stype] 152 | return json.loads(s) 153 | 154 | 155 | def fill_basic(_c, _v): 156 | _outbound = _c["outbound"] 157 | _vnext = _outbound["settings"]["vnext"][0] 158 | # address为服务器域名 后续需要获取IP 159 | _vnext["address"] = _v["add"] 160 | _vnext["port"] = int(_v["port"]) 161 | _vnext["users"][0]["id"] = _v["id"] 162 | _vnext["users"][0]["alterId"] = int(_v["aid"]) 163 | 164 | return _c 165 | 166 | 167 | def vmess2client(_t, _v): 168 | _net = _v["net"] 169 | _type = _v["type"] 170 | # print(_t) 171 | # print('***************') 172 | # print(_v) 173 | _c = fill_basic(_t, _v) 174 | 175 | return _c 176 | 177 | 178 | def read_subscribe(sub_url): 179 | print("Reading from subscribe ...") 180 | headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.3'} 181 | req = urllib.request.Request(url=sub_url, headers=headers) 182 | with urllib.request.urlopen(req) as response: 183 | _subs = response.read() 184 | return base64.b64decode(_subs + b'=' * (-len(_subs) % 4)).decode().splitlines() 185 | 186 | 187 | def jsonDump(obj, fobj): 188 | if option.update is not None: 189 | oconf = json.load(option.update) 190 | if "outbound" not in oconf: 191 | raise KeyError("outbound not found in {}".format(option.update.name)) 192 | 193 | oconf["outbound"] = obj["outbound"] 194 | option.update.close() 195 | with open(option.update.name, 'w') as f: 196 | json.dump(oconf, f, indent=4) 197 | print("Updated") 198 | return 199 | 200 | if option.outbound: 201 | json.dump(obj['outbound'], fobj, indent=4) 202 | else: 203 | json.dump(obj, fobj, indent=4) 204 | 205 | 206 | def select_multiple(lines, myPort): 207 | vmesses = [] 208 | vmessNames = [] 209 | for _v in lines: 210 | _vinfo = parseLink(_v) 211 | if _vinfo is not None: 212 | # - { name: "", type: vmess, server: ***.com, port: ***, uuid: ***, alterId: 2, cipher: none } 213 | # vmesses.append({ "ps": "[{ps}] {add}:{port}/{net}/{id}/{aid}".format(**_vinfo), "vm": _v }) 214 | vmesses.append({"ps": "- {{ name: \"{ps}\",type: vmess, server: {add}, port: {port}, uuid: {id}, alterId: {aid}, cipher: none }}".format(**_vinfo), "vm": _v}) 215 | vmessNames.append({"name": "{ps}".format(**_vinfo)}) 216 | 217 | print("Found {} items.".format(len(vmesses))) 218 | f = open(home + configPath + '/vmessClash.txt', 'w') 219 | f.truncate() 220 | f.close() 221 | f = open(home + configPath + '/v2rayExternal.txt', 'w') 222 | f.truncate() 223 | f.close() 224 | for i, item in enumerate(vmesses): 225 | # print("[{}] - {}".format(i+1, item["ps"])) 226 | # print("{}".format(item["ps"])) 227 | f = open(home + configPath + '/vmessClash.txt', 'a') 228 | f.write("{}\n".format(item["ps"])) 229 | f.close() 230 | 231 | remarks = vmessNames[i]['name'] 232 | # print(remarks) 233 | ln = parseLink(item['vm']) 234 | if ln is None: 235 | return 236 | cc = (vmess2client(load_TPL("CLIENT"), ln)) 237 | cc['inbound']['port'] = int(myPort) + i 238 | lp = cc['inbound']['port'] 239 | serverIP = getIP(cc['outbound']['settings']['vnext'][0]['address']) 240 | if not os.path.exists(home + surgePath): 241 | os.makedirs(home + surgePath) 242 | writepath = home + surgePath + '/' + remarks + '.json' 243 | print( 244 | remarks + ' = external, exec = \"' + home + '/Documents/Surge/config/v2raycore/v2ray\", args = \"' + '--config=' + home + surgePath + '/' + remarks + '.json' + '\", ' + 'local-port = ' + str( 245 | lp) + ', addresses = ' + '\"' + serverIP + '\"') 246 | f = open(home + configPath + '/v2rayExternal.txt', 'a') 247 | f.write( 248 | remarks + ' = external, exec = \"' + home + '/Documents/Surge/config/v2raycore/v2ray\", args = \"' + '--config=' + home + surgePath + '/' + remarks + '.json' + '\", ' + 'local-port = ' + str( 249 | lp) + ', addresses = ' + '\"' + serverIP + '\"' + '\n') 250 | f.close() 251 | if os.path.exists(writepath): 252 | # mode = 'a' if os.path.exists(writepath) else 'w' 253 | with open(writepath, 'w') as f: 254 | json.dump(cc, f, indent=4) 255 | else: 256 | with open(writepath, 'w') as f: 257 | json.dump(cc, f, indent=4) 258 | 259 | # with open(writepath, mode) as f: 260 | # json.dumps(cc, f, indent=4) 261 | 262 | # print(vmessNames) 263 | for i, item in enumerate(vmessNames): 264 | f = open(home + configPath + '/vmessClash.txt', 'a') 265 | f.write(item['name']) 266 | print(item['name'] + ',') 267 | if i != len(vmessNames) - 1: 268 | f.write(',') 269 | f.close() 270 | 271 | 272 | def detect_stdin(): 273 | if sys.stdin.isatty(): 274 | return None 275 | stdindata = sys.stdin.read() 276 | try: 277 | lines = base64.b64decode(stdindata).decode().splitlines() 278 | option.subscribe = "-" 279 | return lines 280 | except (binascii.Error, UnicodeDecodeError): 281 | return stdindata.splitlines() 282 | 283 | 284 | def getIP(domain): 285 | try: 286 | myaddr = socket.gethostbyname(domain) 287 | except BaseException: 288 | myaddr = 'unknown' 289 | return myaddr 290 | 291 | 292 | if __name__ == "__main__": 293 | parser = argparse.ArgumentParser(description="vmess2json convert vmess link to client json config.") 294 | parser.add_argument('-s', 295 | action="store", 296 | default="", 297 | help="read from a subscribe url, display a menu to choose nodes") 298 | parser.add_argument('-p', help="this is the destined port number") 299 | option = parser.parse_args() 300 | if len(option.p) < 4: 301 | option.p = 19829 302 | if len(option.s): 303 | try: 304 | select_multiple(read_subscribe(option.s), option.p) 305 | except (EOFError, KeyboardInterrupt): 306 | print("Bye.") 307 | except BaseException: 308 | traceback.print_exc() 309 | finally: 310 | sys.exit(0) 311 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 WhoJave 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ExternalConfig 2 | 3 | #### 使用说明 4 | 5 | - 项目中使用的python3路径为 `/usr/local/bin/python3`,请自行安装 6 | 7 | - 生成配置的路径为`~/Documents/Surge/config` 8 | 9 | - 请将ss-local文件复制到`~/Documents/Surge/config`目录下 10 | 11 | - 请将v2rayCore相关文件复制到`~/Documents/Surge/config/v2raycore` 12 | 13 | - `~/Documents/Surge/config/external.txt`Surge中可用的SSR External配置文件,如配置参考所示 14 | 15 | - `~/Documents/Surge/config/v2rayExternal.txt`Surge中可用的V2RAY External配置文件,如配置参考所示 16 | 17 | - 关于`ss-local(此处指的是SSR)`[ShadowsocksX-NG-R8](https://github.com/qinyuhang/ShadowsocksX-NG-R/releases)安装后在`~/Library/Application Support/ShadowsocksX-NG/ss-local-2.5.6.9.static`这个路径下可找到 18 | 19 | - 参考:https://community.nssurge.com/d/3-external-proxy-provider 启动后可在`/tmp`路径看到log 20 | 21 | - `v2ray`同理 这里 https://github.com/v2ray/v2ray-core/releases 下载使用 22 | 23 | - Python脚本使用 24 | 25 | ```shell 26 | #进入项目中脚本文件夹 27 | cd ExternalConfig/ExternalConfig/script 28 | #执行如下脚本在指定目录生成配置 29 | python3 RSS.py -s `此外为你的SSR订阅地址` -p 端口号 30 | python3 v2json.py -s `此外为你的V2RAY订阅地址` -p 端口号 31 | #示例: 32 | script git:(master) ✗ python3 RSS.py -s https://www.xxxxxx.com -p 19522 33 | script git:(master) ✗ python3 v2json.py -s https://www.xxxxxx.com -p 19829 34 | ``` 35 | 36 | #### 配置参考: 37 | 38 | >- 示例: 39 | > 40 | >```json 41 | >SSR东京2上海 = external, exec = "/Users/你的用户名/Documents/Surge/config/ss-local", local-port = 19522, args = "-c", args = "/Users/你的用户名/Documents/Surge/config/SSRJson/SSR东京2上海.json", addresses = "服务器IP" 42 | >香港5v2ray = external, exec = "/Users/你的用户名/Documents/Surge/config/v2ray-core/v2ray", local-port = 19829, args = "--config=/Users/你的用户名/Documents/Surge/config/vmessJson/香港5v2ray.json", addresses = "服务器IP" 43 | >``` 44 | > 45 | >注意:上文配置中 `local-port`要与下文json配置中的`local-port`保持一致 46 | > 47 | >- SSR东京2上海.json 48 | > 49 | >```json 50 | >{ 51 | >"local_address" : "127.0.0.1", 52 | >"local_port" : 19522, 53 | >"server" : "服务器地址", 54 | >"server_port" : 8888, 55 | >"method" : "aes-256-cfb", 56 | >"protocol" : "auth_chain_a", 57 | >"protocol_param" : "", 58 | >"timeout" : 60, 59 | >"obfs" : "tls1.2_ticket_auth", 60 | >"obfs_param" : "cloudflare.com", 61 | >"password" : "你的密码" 62 | >} 63 | >``` 64 | > 65 | >- 香港5v2ray.json 66 | > 67 | >```json 68 | >{ 69 | >"log": { 70 | > "loglevel": "info" 71 | >}, 72 | >"inbound": { 73 | > "listen": "127.0.0.1", 74 | > "port": 19829, 75 | > "protocol": "socks", 76 | > "settings": { 77 | > "auth": "noauth", 78 | > "udp": true, 79 | > "ip": "127.0.0.1" 80 | > } 81 | >}, 82 | >"outbound": { 83 | > "protocol": "vmess", 84 | > "settings": { 85 | > "vnext": [ 86 | > { 87 | > "address": "你的服务器", 88 | > "port": 8888, 89 | > "users": [ 90 | > { 91 | > "id": "你的id", 92 | > "alterId": 2 93 | > } 94 | > ] 95 | > } 96 | > ] 97 | > } 98 | >} 99 | >} 100 | > 101 | >``` 102 | > 103 | >注:`v2ray`inboud中配置的port需要与配置文件中的`local-port`一致,更多配置请参考`[v2ray`官网](https://www.v2ray.com/) 104 | > 105 | >- **v2ray转换脚本暂只支持自用机场 -_- 有需要请自行修改脚本** 106 | 107 | --------------------------------------------------------------------------------