├── .build ├── default.Manifest.xml ├── default.init.aardio └── default.main.aardio ├── .gitignore ├── LICENSE ├── README.md ├── app.ico ├── default.aproj ├── forms └── main │ ├── json.aardio │ ├── tools │ ├── github.aardio │ ├── tools.aardio │ └── youtube.aardio │ └── v2ray.aardio ├── lib ├── config.aardio ├── style.aardio └── v2ray │ ├── config.aardio │ └── core.aardio ├── main.aardio ├── pac.txt ├── screenshots ├── config.json.png ├── config.txt.png ├── config.vmess.png └── win2ray.png ├── v2ray-core ├── v2ctl.exe ├── v2ray.exe └── win2ray-default-servers.txt └── win2ray.exe /.build/default.Manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 10 | win2ray 11 | 12 | 13 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 52 | 53 | 54 | 55 | 56 | 57 | True/PM 58 | 59 | 60 | -------------------------------------------------------------------------------- /.build/default.init.aardio: -------------------------------------------------------------------------------- 1 | //发布前触发 2 | import ide; -------------------------------------------------------------------------------- /.build/default.main.aardio: -------------------------------------------------------------------------------- 1 | //此触发器在生成EXE以后执行 2 | import ide; 3 | import fsys; 4 | 5 | //获取生成的EXE文件路径 6 | var publishFile = ide.getPublishPath(); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | v2ray-core/config.json 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 win2ray 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 | # win2ray 2 | 简洁稳定的 V2Ray Windows 客户端, 3 | 本程序使用 [aardio](http://www.aardio.com) 编写,不需要.Net运行库,生成的EXE非常小。 4 | 5 | 软件首次运行时会在当前目录查找 "./v2ray-core/v2ray.exe" 6 | 发行文件仅需要 "./win2ray.exe",可选带上 "./v2ray-core/" 目录( 如果没有找到会自动到v2ray官网下载,不过没有代理服务器下载有时候非常慢 )。 7 | 8 | win2ray 支持批量测试服务器,并选择响应最快的进行连接,启动软件时也会自动连接响应最快的服务器。 9 | 设置活动服务器以后,也会在数秒内自动检测访问国外网站是否正常,如下图: 10 | 11 | ![win2ray](./screenshots/win2ray.png) 12 | 13 | 批量导入各种格式的服务器配置,支持json、vmess链接、ss链接、文本表格格式服务器列表等。 14 | 可选在 ["/v2ray-core/win2ray-default-servers.txt"](./v2ray-core/win2ray-default-servers.txt) 文件中添加默认服务器列表(生成EXE后默认配置自动嵌入到EXE文件,可选删除该文件,也可以继续使用该文件覆盖EXE自带的默认服务器列表)。 15 | 16 | ![文本表格格式服务器列表](./screenshots/config.txt.png) 17 | 18 | ![vmess链接、ss链接格式服务器列表](./screenshots/config.vmess.png) 19 | 20 | ![json格式服务器列表](./screenshots/config.json.png) -------------------------------------------------------------------------------- /app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/app.ico -------------------------------------------------------------------------------- /default.aproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /forms/main/json.aardio: -------------------------------------------------------------------------------- 1 | import fonts.fontAwesome; 2 | import win.ui; 3 | /*DSG{{*/ 4 | var winform = win.form(text="aardio form";right=912;bottom=793;bgcolor=16777215) 5 | winform.add( 6 | btnUpdate={cls="plus";text="更新设置";left=731;top=750;right=863;bottom=781;align="left";bgcolor=11580047;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF0C7';notify=1;textPadding={left=40};z=7}; 7 | editCoreConfig={cls="edit";left=10;top=34;right=903;bottom=744;db=1;dl=1;dr=1;dt=1;edge=1;hide=1;hscroll=1;multiline=1;vscroll=1;z=6}; 8 | editOutbounds={cls="edit";left=9;top=32;right=902;bottom=743;db=1;dl=1;dr=1;dt=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=1}; 9 | lbTip={cls="static";text="可在下面输入JSON数组、或每行一个服务器链接、或每行以空格分开的服务器配置文本:";left=11;top=9;right=899;bottom=29;color=3947580;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);transparent=1;z=8}; 10 | navCoreConfig={cls="plus";text="高级配置( JSON )";left=184;top=750;right=315;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=3}; 11 | navOutbounds={cls="plus";text="服务器配置( JSON )";left=53;top=750;right=184;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=2}; 12 | navRight={cls="plus";left=314;top=750;right=604;bottom=751;bgcolor=16777215;border={color=-16744448};db=1;dl=1;dr=1;forecolor=32768;linearGradient=180;z=4}; 13 | plus={cls="plus";left=9;top=750;right=53;bottom=751;border={color=-16744448};db=1;dl=1;forecolor=32768;z=5} 14 | ) 15 | /*}}*/ 16 | 17 | import config; 18 | import web.json; 19 | import win.ui.tabs; 20 | var tbs = win.ui.tabs(winform.navOutbounds,winform.navCoreConfig,winform.nav06,winform.nav091,winform.navZhengMa,winform.navTxt) 21 | tbs.margin = 0; 22 | 23 | tbs.skin({ 24 | foreground={ 25 | active=0xFFFFFFFF; 26 | default=0x00FFFFFF; 27 | hover=0xFFCCCCCC; 28 | }; 29 | checked={ 30 | foreground={ 31 | default=0x00FFFFFF; 32 | }; 33 | border = { 34 | default = {left=1;right=1;bottom=1;color=0xFF008000} 35 | }; 36 | } 37 | }); 38 | 39 | tbs.onSelchange = function(idx,strip,form){ 40 | if(idx==1){ 41 | winform.editOutbounds.hide = false; 42 | winform.editCoreConfig.hide = true; 43 | winform.lbTip.text = `可在下面输入JSON数组、或每行一个服务器链接、或每行以空格分开的服务器配置文本:` 44 | } 45 | else { 46 | winform.editOutbounds.hide = true; 47 | winform.editCoreConfig.hide = false; 48 | winform.lbTip.text = `outbounds[1]会被自动替换为服务器数组,请勿修改: ` 49 | } 50 | } 51 | tbs.selIndex = 1; 52 | 53 | import style; 54 | winform.btnUpdate.skin(style.primaryButton); 55 | winform.btnUpdate.oncommand = function(id,event){ 56 | winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}; 57 | 58 | if(tbs.selIndex==1){ 59 | if(..string.match(winform.editOutbounds.text,"%\[\]")){ 60 | var cfg,err = web.json.tryParse(winform.editOutbounds.text); 61 | if(!cfg){ 62 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); 63 | winform.btnUpdate.disabledText = null; 64 | return; 65 | } 66 | config.proxy.outbounds = cfg : {}; 67 | } 68 | else { 69 | var outbounds = v2ray.config.importFromString(winform.editOutbounds.text); 70 | config.proxy.outbounds = outbounds : {}; 71 | winform.editOutbounds.text = web.json.stringify(outbounds,true); 72 | } 73 | 74 | config.proxy.save(); 75 | winform.editOutbounds.modified = false; 76 | publish("config.proxy.outbounds.changed",cfg) 77 | } 78 | elseif(tbs.selIndex==2) { 79 | var cfg,err = web.json.tryParse(winform.editCoreConfig.text); 80 | if(type(cfg)!==type.table){ 81 | winform.editCoreConfig.showErrorTip(,string.concat("JSON语法错误 ",err)); 82 | winform.btnUpdate.disabledText = null; 83 | return; 84 | } 85 | 86 | if(cfg.outbounds[[1]][["tag"]]!="proxy"){ 87 | winform.msgErr(`outbounds[1]必须指定为{"tag":"proxy"}`); 88 | winform.btnUpdate.disabledText = null; 89 | return; 90 | } 91 | 92 | config.core.default = cfg; 93 | config.core.save(); 94 | publish("config.proxy.outbounds.changed",cfg) 95 | } 96 | 97 | win.delay(500); 98 | winform.btnUpdate.disabledText = null; 99 | winform.msgOk("配置已更新"); 100 | } 101 | 102 | 103 | import v2ray.config; 104 | winform.editOutbounds.enablePopMenu(function(){ 105 | if(tbs.selIndex==1){ 106 | var menu = { 107 | { /*---分隔线---*/ }; 108 | { "自剪贴板批量导入vmess:// 或 ss:// 链接"; 109 | function(id){ 110 | var str = winform.editOutbounds.text; 111 | 112 | 113 | var outbounds = v2ray.config.importFromClip(); 114 | if(#outbounds){ 115 | 116 | if(..string.match(winform.editOutbounds.text,"%\[\]")){ 117 | var cfg,err = web.json.tryParse(winform.editOutbounds.text); 118 | if(!cfg){ 119 | winform.editOutbounds.showErrorTip(,string.concat("当前配置存在JSON语法错误 ",err)); 120 | return; 121 | } 122 | 123 | ..table.append(cfg,outbounds); 124 | winform.editOutbounds.text = ..web.json.stringify(cfg,true); 125 | } 126 | else { 127 | var str = v2ray.config.exportToString(outbounds); 128 | winform.editOutbounds.text = winform.editOutbounds.text + '\r\n' + str; 129 | } 130 | 131 | winform.msgOk("已成功导入" + #outbounds + "个服务器"); 132 | winform.editOutbounds.modified = true; 133 | winform.editOutbounds.setFocus(); 134 | return; 135 | } 136 | 137 | winform.msgFrown("未导入服务器, 请先复制 vmess:// 或 ss:// 链接!") 138 | } 139 | }; 140 | } 141 | 142 | if(..string.match(winform.editOutbounds.text,"%\[\]")){ 143 | menu[3] = { "转换为 vmess:// 或 ss:// 链接"; 144 | function(id){ 145 | var cfg,err = web.json.tryParse(winform.editOutbounds.text); 146 | if(!cfg){ 147 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); 148 | return; 149 | } 150 | 151 | var str = v2ray.config.exportToString(cfg); 152 | if(str){ 153 | winform.editOutbounds.text = str; 154 | winform.editOutbounds.modified = true; 155 | } 156 | } 157 | }; 158 | menu[4] = { "转换为文本格式"; 159 | function(id){ 160 | var cfg,err = web.json.tryParse(winform.editOutbounds.text); 161 | if(!cfg){ 162 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err)); 163 | return; 164 | } 165 | 166 | var outstr = {}; 167 | for i,outbound in table.eachIndex(cfg){ 168 | if(outbound.protocol != "shadowsocks"){ 169 | table.push(outstr, string.concat( outbound.address,'\t' 170 | ,outbound.port,'\t' 171 | ,outbound.id,,'\t' 172 | ,outbound.network,'\t' 173 | ,outbound.path,'\t' 174 | ,outbound.tls ) ); 175 | } 176 | else { 177 | table.push(outstr, string.concat( outbound.address,'\t' 178 | ,outbound.port,'\t' 179 | ,outbound.id,,'\t' 180 | ,'shadowsocks\t' 181 | ,outbound.security) ); 182 | } 183 | } 184 | 185 | winform.editOutbounds.text = string.join(outstr,'\r\n'); 186 | winform.editOutbounds.modified = true; 187 | } 188 | }; 189 | } 190 | else { 191 | menu[3] = { "转换为 JSON"; 192 | function(id){ 193 | import web.json; 194 | var outbounds = v2ray.config.importFromString(winform.editOutbounds.text); 195 | if(outbounds){ 196 | winform.editOutbounds.text = web.json.stringify(outbounds,true); 197 | winform.editOutbounds.modified = true; 198 | } 199 | } 200 | }; 201 | } 202 | 203 | table.push(menu,{ /*---分隔线---*/ }); 204 | if(winform.editOutbounds.modified){ 205 | table.push(menu,{ "恢复为当前使用的服务器列表"; 206 | function(id){ 207 | winform.editOutbounds.text = web.json.stringify( 208 | config.proxy.outbounds,true 209 | ) 210 | winform.editOutbounds.modified = false; 211 | } 212 | }); 213 | } 214 | 215 | table.push(menu,{ "恢复为默认服务器列表"; 216 | function(id){ 217 | ..config.__loadDefaultOutbounds(); 218 | publish("config.proxy.outbounds.changed",cfg); 219 | } 220 | }); 221 | 222 | return menu; 223 | } 224 | }) 225 | 226 | subscribe("config.proxy.outbounds.config.changed",function(){ 227 | if(winform.editOutbounds.modified){ 228 | return; 229 | } 230 | 231 | winform.editOutbounds.text = web.json.stringify( 232 | config.proxy.outbounds,true 233 | ) 234 | 235 | winform.editOutbounds.modified = false; 236 | } ) 237 | 238 | winform.editOutbounds.text = #config.proxy.outbounds ? web.json.stringify( 239 | config.proxy.outbounds ,true 240 | ) : "[]" 241 | winform.editOutbounds.modified = false; 242 | 243 | winform.editCoreConfig.text = web.json.stringify( 244 | config.core.default,true 245 | ) 246 | 247 | winform.show(); 248 | win.loopMessage(); 249 | return winform; -------------------------------------------------------------------------------- /forms/main/tools/github.aardio: -------------------------------------------------------------------------------- 1 | //RUNAS//github优化 2 | import fonts.fontAwesome; 3 | import win.ui; 4 | /*DSG{{*/ 5 | var winform = win.form(text="github.com 网速优化工具";right=655;bottom=281;bgcolor=16777215;border="none";max=false) 6 | winform.add( 7 | bk={cls="bk";left=0;top=0;right=659;bottom=34;bgcolor=12632256;z=8}; 8 | cmbIpCidrs={cls="combobox";left=49;top=111;right=328;bottom=137;edge=1;items={};mode="dropdown";z=1}; 9 | editIpCurrent={cls="edit";left=118;top=206;right=366;bottom=230;edge=1;z=5}; 10 | plusExploreHosts={cls="plus";text='\uF07C 浏览hosts文件';left=450;top=204;right=607;bottom=235;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=7}; 11 | plusUpdateDns={cls="plus";text='\uF0AD 更改 github.com 域名解析到选定IP';left=116;top=158;right=505;bottom=189;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=3}; 12 | plusUpdateIps={cls="plus";text='\uF021 获取最新IP列表 / 测速';left=345;top=108;right=607;bottom=139;bgcolor=-6371181;font=LOGFONT(h=-15;name='FontAwesome';charset=0);notify=1;z=2}; 13 | static={cls="static";text="本工具使用github官网接口获取最新IP列表,从github下载zip的速度与此无关。";left=49;top=50;right=583;bottom=86;font=LOGFONT(h=-13);transparent=1;z=4}; 14 | static2={cls="static";text="当前指向IP:";left=27;top=208;right=111;bottom=228;align="right";transparent=1;z=6} 15 | ) 16 | /*}}*/ 17 | 18 | winform.cmbIpCidrs.onListChange = function(){ 19 | winform.setTimeout( 20 | function(){ 21 | var ip = string.match(winform.cmbIpCidrs.selText,"\d+\.\d+\.\d+\.\d+"); 22 | if(!ip){ 23 | return ; 24 | } 25 | winform.plusUpdateDns.text = "更改 github.com 域名解析到:" + ip 26 | } 27 | ); 28 | } 29 | 30 | import wsock; 31 | import fsys.config; 32 | config = fsys.config( io.appData("/aardio/github-ip-tools/") ); 33 | winform.plusUpdateIps.oncommand = function(id,event){ 34 | winform.plusUpdateIps.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} 35 | winform.text = "请稍候,正在测试github.com所有可用IP的响应速度" 36 | 37 | var metaInfo = win.invoke( 38 | function(){ 39 | import win; 40 | import web.rest.jsonClient; 41 | var http = web.rest.jsonClient(); 42 | var github = http.api("https://api.github.com/") 43 | 44 | return github.meta.get() : { git = { 45 | "192.30.252.0"; 46 | "185.199.108.0"; 47 | "140.82.112.0"; 48 | "13.114.40.48"; 49 | "13.229.188.59"; 50 | "13.234.176.102"; 51 | "13.234.210.38"; 52 | "13.236.229.21"; 53 | "13.237.44.5"; 54 | "13.250.177.223"; 55 | "15.164.81.167"; 56 | "18.194.104.89"; 57 | "18.195.85.27"; 58 | "35.159.8.160"; 59 | "52.192.72.89"; 60 | "52.64.108.95"; 61 | "52.69.186.44"; 62 | "52.74.223.119"; 63 | "52.78.231.108" 64 | } }; 65 | } 66 | ) 67 | 68 | if(metaInfo[["git"]]){ 69 | config.meta.data = table.map(metaInfo.git,lambda(v)..string.match(v,"^\d+\.\d+\.\d+\.\d+")) 70 | } 71 | elseif(!config.meta.data){ 72 | winform.msgboxErr("您的操作系统版本过低") 73 | } 74 | 75 | var pingThread = function( ip ) { 76 | import wsock.tcp.client; 77 | 78 | var result = 0; 79 | for(i=1;4;1){ 80 | 81 | var beginTick = ..time.tick() 82 | var tcp = wsock.tcp.client() 83 | 84 | tcp.setTimeouts(1000,1000); 85 | if( ! tcp.connectTimeout(ip,80,2) ){ 86 | return; 87 | }; 88 | 89 | sendData =/*********** 90 | GET / HTTP/1.1 91 | Host: www.github.com 92 | Connection: close 93 | User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) 94 | Accept: */*; 95 | Accept-Language: zh-CN,zh; 96 | Accept-Charset:utf-8; 97 | ***********/ 98 | tcp.write( sendData + '\r\n\r\n' ) 99 | 100 | var rep = tcp.readAll(); 101 | tcp.close(); 102 | 103 | if( rep && ..string.startWith(rep,"HTTP/1.1 301 Moved Permanently") ){ 104 | result = result + ((..time.tick() - beginTick)/1000); 105 | } 106 | else { 107 | return; 108 | } 109 | 110 | } 111 | 112 | return ip,math.round(result/4,2); 113 | 114 | } 115 | 116 | import thread.manage; 117 | manage = thread.manage(#config.meta.data) 118 | 119 | var ipData = {} 120 | for(k,ip in config.meta.data){ 121 | manage.createSuspended(pingThread,ip).onEnd = function(ip,sec){ 122 | if(ip && sec!==null ) { 123 | table.push(ipData,ip + " 响应速度:" + sec + "秒"); 124 | winform.cmbIpCidrs.items = ipData; 125 | winform.cmbIpCidrs.selIndex = 1; 126 | } 127 | } 128 | } 129 | 130 | manage.resume(); 131 | manage.waitClose(); 132 | 133 | winform.cmbIpCidrs.items = ipData; 134 | winform.cmbIpCidrs.selIndex = 1; 135 | winform.cmbIpCidrs.onListChange(); 136 | 137 | winform.editIpCurrent.text = wsock.getIp("www.github.com") 138 | 139 | winform.text = "github.com 网速优化工具" 140 | winform.plusUpdateIps.disabledText = null; 141 | } 142 | 143 | import fsys.hosts; 144 | winform.plusUpdateDns.oncommand = function(id,event){ 145 | var ip = winform.cmbIpCidrs.text; 146 | if(!#ip){ 147 | winform.msgboxErr("请选选择IP地址") 148 | return; 149 | } 150 | 151 | ip = string.match(ip,"\d+\.\d+\.\d+\.\d+"); 152 | if( ip == winform.editIpCurrent.text ) return winform.msgboxErr("域名之前已经解析到该IP地址") 153 | 154 | winform.plusUpdateDns.disabledText = "正在更新IP" 155 | 156 | fsys.hosts.ownCacls(); 157 | fsys.hosts.update( 158 | ["www.github.com"] = ip; 159 | ["github.com"] = ip; 160 | ) 161 | 162 | win.delay(1000); 163 | winform.editIpCurrent.text = wsock.getIp("www.github.com"); 164 | winform.plusUpdateDns.disabledText = null; 165 | 166 | if( ip != winform.editIpCurrent.text ){ 167 | winform.msgboxErr("修改hosts文件失败,如果hosts文件被其他软件锁定时请先解除锁定,也可以搜索网上教程试试设置文件权限") 168 | } 169 | } 170 | 171 | winform.plusExploreHosts.skin( 172 | background = { 173 | hover = "/res/images/btn-hover.png"; 174 | focus = "/res/images/btn-focus.jpg"; 175 | active = "/res/images/btn-active.png"; 176 | disabled = "/res/images/btn-disabled.png"; 177 | } 178 | ) 179 | winform.plusExploreHosts.oncommand = function(id,event){ 180 | import process; 181 | process.exploreSelect(fsys.hosts.path) 182 | } 183 | 184 | winform.plusUpdateDns.skin({ 185 | background={ 186 | default=0xFF93C89E; 187 | hover=0xFF928BB3 188 | } 189 | }) 190 | 191 | winform.plusUpdateIps.skin({ 192 | background={ 193 | default=0xFF93C89E; 194 | hover=0xFF928BB3 195 | } 196 | }) 197 | 198 | winform.plusExploreHosts.skin({ 199 | background={ 200 | default=0xFF93C89E; 201 | hover=0xFF928BB3 202 | } 203 | }) 204 | 205 | import win.ui.simpleWindow2; 206 | win.ui.simpleWindow2(winform); 207 | 208 | winform.show() 209 | winform.plusUpdateIps.oncommand(); 210 | 211 | win.loopMessage(); -------------------------------------------------------------------------------- /forms/main/tools/tools.aardio: -------------------------------------------------------------------------------- 1 | import fonts.fontAwesome; 2 | import win.ui; 3 | /*DSG{{*/ 4 | var winform = win.form(text="aardio form";right=759;bottom=469;bgcolor=16777215) 5 | winform.add( 6 | btnAardio={cls="plus";text="aardio 桌面软件快速开发";left=44;top=257;right=295;bottom=299;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF17A';notify=1;textPadding={left=50};z=3}; 7 | btnGitHub={cls="plus";text="github 网速优化";left=44;top=187;right=280;bottom=229;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF09B';notify=1;textPadding={left=50};z=2}; 8 | btnUpdateSystemTime={cls="plus";text="同步系统时间( 修正 v2ray 连接报错 )";left=44;top=46;right=430;bottom=88;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF017';notify=1;textPadding={left=50};z=4}; 9 | btnYoutube={cls="plus";text="youtube 视频下载工具";left=44;top=116;right=280;bottom=158;align="left";color=3947580;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-27;name='FontAwesome');padding={left=18}};iconText='\uF167';notify=1;textPadding={left=50};z=1} 10 | ) 11 | /*}}*/ 12 | 13 | import style; 14 | winform.btnYoutube.skin(style.plainButton) 15 | 16 | var frmYoutube; 17 | winform.btnYoutube.oncommand = function(id,event){ 18 | if(frmYoutube&&win.isWindow(frmYoutube.hwnd)){ 19 | if(win.isIconic(frmYoutube.hwnd)){ 20 | frmYoutube.show(9/*_SW_RESTORE*/); 21 | } 22 | 23 | frmYoutube.show(); 24 | return; 25 | } 26 | 27 | frmYoutube = winform.loadForm("\forms\main\tools\youtube.aardio"); 28 | frmYoutube.show(); 29 | } 30 | 31 | import process; 32 | winform.btnGitHub.skin(style.plainButton) 33 | winform.btnGitHub.oncommand = function(id,event){ 34 | if(_STUDIO_INVOKED){ 35 | winform.msgboxErr("请在发布后运行此功能"); 36 | return; 37 | } 38 | 39 | process.execute(io._exepath,"/github","runas"); 40 | } 41 | 42 | winform.btnAardio.skin(style.plainButton) 43 | winform.btnAardio.oncommand = function(id,event){ 44 | process.openUrl("http://www.aardio.com") 45 | } 46 | 47 | winform.btnUpdateSystemTime.skin(style.plainButton) 48 | winform.btnUpdateSystemTime.oncommand = function(id,event){ 49 | if(_STUDIO_INVOKED){ 50 | winform.msgboxErr("请在发布后运行此功能"); 51 | return; 52 | } 53 | 54 | process.execute(io._exepath,"/updateTime","runas"); 55 | } 56 | 57 | winform.show(); 58 | win.loopMessage(); -------------------------------------------------------------------------------- /forms/main/tools/youtube.aardio: -------------------------------------------------------------------------------- 1 | import fonts.fontAwesome; 2 | import win.ui; 3 | import win.ui.atom; 4 | /*DSG{{*/ 5 | var winform = win.form(text="youtube 视频下载工具(点击视频链接即可下载)";right=759;bottom=469) 6 | winform.add( 7 | btnVideoInfo={cls="button";text="获取视频下载地址";left=511;top=27;right=732;bottom=60;dr=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=3}; 8 | editInfo={cls="richedit";left=29;top=83;right=735;bottom=445;autohscroll=false;db=1;dl=1;dr=1;dt=1;edge=1;link=1;multiline=1;vscroll=1;z=1}; 9 | editVideoUrl={cls="edit";text="https://www.youtube.com/watch?v=ZFA5Rax0ypU";left=27;top=29;right=499;bottom=58;dl=1;dr=1;dt=1;edge=1;multiline=1;z=2} 10 | ) 11 | /*}}*/ 12 | 13 | winform.btnVideoInfo.oncommand = function(id,event){ 14 | var url = winform.editVideoUrl.text; 15 | var vid = string.match(url,"v=([\w\-]+)"); 16 | if(!vid){ 17 | return winform.editVideoUrl.showErrorTip(,"请输入正确的视频地址"); 18 | } 19 | 20 | winform.btnVideoInfo.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} 21 | thread.invoke( 22 | function(winform,vid){ 23 | import web.rest.jsonLiteClient; 24 | var http = web.rest.jsonLiteClient(); 25 | 26 | var videoApi = http.api("https://www.youtube.com/get_video_info?video_id={video_id}"); 27 | var info = videoApi[vid].get(); 28 | 29 | if(!info){ 30 | winform.editInfo.text = "网络错误"; 31 | winform.btnVideoInfo.disabledText = null; 32 | } 33 | 34 | winform.editInfo.text = ""; 35 | winform.editInfo.print( "视频作者:",info.player_response.videoDetails.author); 36 | winform.editInfo.print( "视频标题:",info.player_response.videoDetails.title); 37 | winform.editInfo.print( "视频说明:",info.player_response.videoDetails.shortDescription); 38 | winform.videoTitle = info.player_response.videoDetails.title; 39 | 40 | for(i,v in info.player_response.streamingData.adaptiveFormats){ 41 | if(!string.indexOf(v.mimeType,"audio/mp4")){ 42 | continue; 43 | } 44 | 45 | winform.editInfo.print(); 46 | winform.editInfo.print("音频质量:",v.quality); 47 | winform.editInfo.print("音频地址:",v.url); 48 | } 49 | 50 | for(i,v in info.player_response.streamingData.formats){ 51 | if(!string.indexOf(v.mimeType,"video/mp4")){ 52 | continue; 53 | } 54 | 55 | winform.editInfo.print(); 56 | winform.editInfo.print("视频质量:",v.qualityLabel); 57 | winform.editInfo.print("视频地址(含音频):",v.url); 58 | } 59 | 60 | 61 | var captionTracks = info.player_response.captions[["playerCaptionsTracklistRenderer"]][["captionTracks"]]; 62 | if(info.captions[["playerCaptionsTracklistRenderer"]][["captionTracks"]]){ 63 | if(#captionTracks){ 64 | for(k,v in captionTracks){ 65 | if(v.languageCode=="en"){ 66 | var str = http.get(v.baseUrl) 67 | winform.editInfo.print(str); 68 | break 69 | } 70 | } 71 | 72 | } 73 | } 74 | 75 | winform.editInfo.setFocus(); 76 | winform.btnVideoInfo.disabledText = null; 77 | },winform,vid 78 | ) 79 | } 80 | 81 | import fsys.dlg; 82 | import inet.downBox; 83 | winform.editInfo.onlink=function(message,href){ 84 | if( message = 0x202/*_WM_LBUTTONUP*/ ) { 85 | var path = fsys.dlg.open("*.mp4|*.mp4","请选择下载路径",,winform,,fsys.path.validName(winform.videoTitle)) 86 | if(!path) return; 87 | 88 | var downBox = inet.downBox(winform,"下载视频"); 89 | downBox.download(href,path); 90 | } 91 | } 92 | 93 | winform.show(); 94 | win.loopMessage(); -------------------------------------------------------------------------------- /forms/main/v2ray.aardio: -------------------------------------------------------------------------------- 1 | import fonts.fontAwesome; 2 | import win.ui; 3 | import win.ui.atom; 4 | /*DSG{{*/ 5 | var frmV2ray = win.form(text="win2ray ";right=959;bottom=591;bgcolor=16777215) 6 | frmV2ray.add( 7 | btnImportServerFromClipBd={cls="plus";text="批量导入链接";left=577;top=364;right=710;bottom=400;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF196 ';notify=1;textPadding={left=30};z=8}; 8 | btnTcping={cls="plus";text="自动选择响应最快服务器";left=712;top=366;right=941;bottom=398;align="left";bgcolor=11580047;border={radius=4};db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=18}};iconText='\uF012';notify=1;textPadding={left=42};z=3}; 9 | btnUpdatePac={cls="plus";text="更新PAC文件";left=442;top=364;right=574;bottom=400;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=12}};iconText='\uF1C4';notify=1;textPadding={left=30};z=7}; 10 | edit={cls="edit";left=6;top=405;right=953;bottom=585;bgcolor=0;color=16777215;db=1;dl=1;dr=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=2}; 11 | listview={cls="listview";left=4;top=5;right=954;bottom=358;db=1;dl=1;dr=1;dt=1;edge=1;fullRow=1;z=1}; 12 | radioProxy={cls="radiobutton";text="全局代理";left=148;top=370;right=245;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=4}; 13 | radioProxyDirect={cls="radiobutton";text="不使用代理";left=33;top=370;right=139;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=6}; 14 | radioProxyPac={cls="radiobutton";text="PAC代理";left=253;top=370;right=340;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=5} 15 | ) 16 | /*}}*/ 17 | 18 | frmV2ray.show(); 19 | frmV2ray.listview.insertColumn("类型",100) 20 | frmV2ray.listview.insertColumn("服务器",200) 21 | frmV2ray.listview.insertColumn("端口",70) 22 | frmV2ray.listview.insertColumn("加密",90) 23 | frmV2ray.listview.insertColumn("协议",50) 24 | frmV2ray.listview.insertColumn("响应速度",80) 25 | frmV2ray.listview.insertColumn("状态",-1) 26 | 27 | import config; 28 | import v2ray.core; 29 | var activeOutbound = function(outboundIndex,outboundAddress){ 30 | if( v2ray.core.restart(frmV2ray.edit,config.proxy.outbounds[outboundIndex]) ){ 31 | 32 | ..thread.invoke( 33 | function(frmV2ray,outboundIndex,outboundAddress,port){ 34 | sleep(1000); 35 | import wsock.tcp.socks5Client; 36 | 37 | var client = wsock.tcp.socks5Client("127.0.0.1",port); 38 | client.setTimeouts(1000,1000); 39 | if(client.connect("www.google.com",80) ){ 40 | var sendData =/*********** 41 | GET / HTTP/1.1 42 | Host: www.google.com 43 | Connection: close 44 | User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) 45 | Accept: */*; 46 | Accept-Language: zh-CN,zh; 47 | Accept-Charset:utf-8; 48 | ***********/ 49 | client.write( sendData + '\r\n\r\n' ) 50 | var rep = client.read(9); 51 | client.close(); 52 | 53 | if(outboundAddress!=frmV2ray.listview.getItemText(outboundIndex,2)){ 54 | return; 55 | } 56 | 57 | if( rep && ..string.startWith(rep,"HTTP/1.1 ") ){ 58 | 59 | import inet.http; 60 | var http = inet.http(,"SOCKS=127.0.0.1:"+port); 61 | http.setTimeouts(1000,2000,2000); 62 | var html = http.get("https://www.google.com"); 63 | http.close(); 64 | 65 | if( html ){ 66 | frmV2ray.onStartV2rayComplete(outboundIndex); 67 | return; 68 | } 69 | } 70 | } 71 | 72 | frmV2ray.onStartV2rayFailed(outboundIndex); 73 | },frmV2ray,outboundIndex,outboundAddress,v2ray.core.getPort() 74 | ) 75 | } 76 | } 77 | 78 | frmV2ray.onStartV2rayComplete = function(outboundIndex){ 79 | frmV2ray.listview.ensureVisible(outboundIndex); 80 | frmV2ray.listview.setItemText("活动服务器:正常",outboundIndex,7); 81 | frmV2ray.edit.print("已切换到服务器:",frmV2ray.listview.getItemText(outboundIndex,2)); 82 | if(frmV2ray.listview.getItemText(outboundIndex,6)=="不可用"){ 83 | frmV2ray.listview.setItemText("...",outboundIndex,6); 84 | } 85 | 86 | frmV2ray.onTcpingReturn = function(){} 87 | frmV2ray.btnTcping.disabledText = null; 88 | } 89 | 90 | frmV2ray.onStartV2rayFailed = function(outboundIndex){ 91 | frmV2ray.listview.ensureVisible(outboundIndex); 92 | frmV2ray.listview.setItemText("活动服务器:异常",outboundIndex,7); 93 | frmV2ray.edit.print("已切换到服务器:",frmV2ray.listview.getItemText(outboundIndex,2)); 94 | frmV2ray.btnTcping.disabledText = null; 95 | } 96 | 97 | var tcping = function(frmV2ray,outboundIndex,address){ 98 | import wsock.tcp.client; 99 | var item = frmV2ray.listview.items[outboundIndex]; 100 | 101 | var timeout = 0; 102 | for(i=1;8;1){ 103 | var client = wsock.tcp.client(); 104 | var tickBegin = time.tick(); 105 | if(client.connectTimeout(item[2],tonumber(item[3]),3)){ 106 | var ret = client.send("."); 107 | client.close(); 108 | 109 | if( ret != 1){ 110 | frmV2ray.listview.setItemText("不可用",outboundIndex,6); 111 | frmV2ray.onTcpingReturn(outboundIndex,address,false); 112 | return; 113 | } 114 | timeout = timeout + (time.tick() - tickBegin); 115 | } 116 | else { 117 | client.close(); 118 | frmV2ray.listview.setItemText("不可用",outboundIndex,6); 119 | frmV2ray.onTcpingReturn(outboundIndex,address,false); 120 | return; 121 | } 122 | } 123 | 124 | frmV2ray.onTcpingReturn(outboundIndex,address,true); 125 | frmV2ray.listview.setItemText(math.round(timeout / 8 / 1000,2)+"秒",outboundIndex,6); 126 | }; 127 | 128 | import style; 129 | frmV2ray.btnTcping.skin(style.primaryButton); 130 | frmV2ray.btnTcping.oncommand = function(id,event){ 131 | 132 | var items = frmV2ray.listview.items; 133 | if(#items){ 134 | frmV2ray.btnTcping.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} 135 | if(!v2ray.core.getPath()){ 136 | frmV2ray.btnTcping.disabledText = null; 137 | frmV2ray.msgErr("下载 v2ray.exe 失败") 138 | return; 139 | } 140 | 141 | frmV2ray.onTcpingReturn = function(outboundIndex,address,succeeded){ 142 | if(address!=frmV2ray.listview.getItemText(outboundIndex,2)){ 143 | return; 144 | } 145 | 146 | if(succeeded){ 147 | frmV2ray.onTcpingReturn = function(outboundIndex){} 148 | activeOutbound(outboundIndex,address); 149 | } 150 | } 151 | 152 | for b,v in table.eachIndex(config.proxy.outbounds){ 153 | frmV2ray.listview.setItemText("...",b,6); 154 | frmV2ray.listview.setItemText("",b,7); 155 | } 156 | 157 | var handles = {} 158 | thread.createSuspended(true); 159 | for(i=1;#items;1){ 160 | var h = thread.create(tcping,frmV2ray,i,frmV2ray.listview.getItemText(i,2)); 161 | table.push(handles,h); 162 | } 163 | thread.createSuspended(false); 164 | 165 | for(i=1;#handles;1){ 166 | var h = handles[i]; 167 | thread.resume(h); 168 | raw.closehandle(h); 169 | } 170 | 171 | ..thread.waitOne(handles); 172 | frmV2ray.btnTcping.disabledText = null; 173 | } 174 | else { 175 | if(id) frmV2ray.msgWarn("请先添加服务器") 176 | } 177 | } 178 | 179 | frmV2ray.onDestroy = function(){ 180 | v2ray.core.stop(); 181 | } 182 | 183 | frmV2ray.listview.onnotify = function(id,code,ptr){ 184 | select(code) { 185 | case 0xFFFFFFFD/*_NM_DBLCLK*/ { 186 | var nm = frmV2ray.listview.getNotifyMessage(code,ptr); 187 | if( nm ){ 188 | frmV2ray.onTcpingReturn = function(i){} 189 | frmV2ray.btnTcping.disabledText = null; 190 | 191 | for b,v in table.eachIndex(config.proxy.outbounds){ 192 | frmV2ray.listview.setItemText("",b,7); 193 | } 194 | activeOutbound(nm.iItem,frmV2ray.listview.getItemText(nm.iItem,2)); 195 | } 196 | } 197 | case 0xFFFFFFFB/*_NM_RCLICK*/ { 198 | var x,y = win.getCursorPos(); 199 | var nm = frmV2ray.listview.getNotifyMessage(code,ptr); 200 | if(!nm) return; 201 | 202 | var currentIdx = nm.iItem; 203 | var popmenu = win.ui.popmenu(frmV2ray); 204 | popmenu.add('设为活动服务器( 鼠标双击 )',function(id){ 205 | if(currentIdx){ 206 | frmV2ray.onTcpingReturn = function(i){} 207 | frmV2ray.btnTcping.disabledText = null; 208 | 209 | for b,v in table.eachIndex(config.proxy.outbounds){ 210 | frmV2ray.listview.setItemText("",b,7); 211 | } 212 | activeOutbound(currentIdx,frmV2ray.listview.getItemText(currentIdx,2)) 213 | } 214 | }); 215 | popmenu.add('复制服务器链接',function(id){ 216 | if(currentIdx){ 217 | import v2ray.config; 218 | import win.clip; 219 | 220 | var str = v2ray.config.exportToString({config.proxy.outbounds[currentIdx]}); 221 | if(str){ 222 | win.clip.write(str); 223 | frmV2ray.edit.print("已复制链接:",str); 224 | } 225 | } 226 | }); 227 | popmenu.add(); 228 | popmenu.add('删除服务器',function(id){ 229 | if(currentIdx){ 230 | frmV2ray.listview.delItem(currentIdx); 231 | ..table.remove(config.proxy.outbounds,currentIdx); 232 | publish("config.proxy.outbounds.config.changed"); 233 | } 234 | }); 235 | popmenu.popup(x,y,true); 236 | } 237 | } 238 | } 239 | 240 | subscribe("config.proxy.outbounds.changed",function(){ 241 | config.proxy.outbounds.fields = {"protocol";"address";"port";"security";"network"}; 242 | frmV2ray.listview.setTable(config.proxy.outbounds); 243 | 244 | frmV2ray.btnTcping.oncommand(); 245 | } ) 246 | 247 | import process; 248 | process.kill("v2ray.exe"); 249 | if(#config.proxy.outbounds){ 250 | frmV2ray.setTimeout( 251 | function(){ 252 | publish("config.proxy.outbounds.changed"); 253 | },1000 254 | ); 255 | } 256 | 257 | subscribe("config.proxy.mode.changed",function(...){ 258 | frmV2ray.radioProxyPac.checked = false; 259 | frmV2ray.radioProxy.checked = false; 260 | frmV2ray.radioProxyDirect.checked = false; 261 | 262 | if(config.proxy.mode = "pac"){ 263 | frmV2ray.radioProxyPac.checked = true; 264 | } 265 | elseif(config.proxy.mode = "proxy"){ 266 | frmV2ray.radioProxy.checked = true; 267 | } 268 | else{ 269 | frmV2ray.radioProxyDirect.checked = true; 270 | } 271 | } ) 272 | publish("config.proxy.mode.changed"); 273 | 274 | var updatProxySetting = function(){ 275 | if(frmV2ray.radioProxyPac.checked){ 276 | config.proxy.mode = "pac"; 277 | inet.conn.setProxyAutoConfig(,v2ray.core.getPacUrl() ) 278 | } 279 | elseif(frmV2ray.radioProxy.checked){ 280 | config.proxy.mode = "proxy"; 281 | inet.conn.setProxy(,"SOCKS=127.0.0.1:"+v2ray.core.getPort()); 282 | } 283 | else { 284 | config.proxy.mode = "direct"; 285 | inet.conn.setProxy(); 286 | } 287 | 288 | config.proxy.save(); 289 | } 290 | frmV2ray.radioProxyPac.oncommand = updatProxySetting; 291 | frmV2ray.radioProxy.oncommand = updatProxySetting; 292 | frmV2ray.radioProxyDirect.oncommand = updatProxySetting; 293 | 294 | import win.dlg.message 295 | win.dlg.message.install() 296 | frmV2ray.btnUpdatePac.skin(style.plainButton) 297 | frmV2ray.btnUpdatePac.oncommand = function(id,event){ 298 | frmV2ray.btnUpdatePac.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'} 299 | thread.invoke( 300 | function(frmV2ray){ 301 | import crypt; 302 | import web.rest.jsonLiteClient; 303 | 304 | var http = web.rest.jsonLiteClient(); 305 | var github = http.api("https://api.github.com"); 306 | 307 | var result = github.repos["petronny"]["gfwlist2pac"].contents["gfwlist.pac"].get(); 308 | if(result[["content"]] && result[["encoding"]]=="base64"){ 309 | content = crypt.decodeBin(result[["content"]]); 310 | string.save(..io.appData("/win2ray/pac.txt"), content); 311 | frmV2ray.msgOk("PAC文件已更新到最新版本"); 312 | } 313 | else { 314 | frmV2ray.msgFrown("PAC文件更新失败,建议开启全局代理后重试。") 315 | } 316 | frmV2ray.btnUpdatePac.disabledText = null; 317 | },frmV2ray 318 | ) 319 | } 320 | 321 | frmV2ray.btnImportServerFromClipBd.skin(style.plainButton) 322 | frmV2ray.btnImportServerFromClipBd.oncommand = function(id,event){ 323 | var outbounds = v2ray.config.importFromClip(); 324 | if(#outbounds){ 325 | ..table.append(config.proxy.outbounds,outbounds); 326 | publish("config.proxy.outbounds.changed"); 327 | publish("config.proxy.outbounds.config.changed"); 328 | frmV2ray.msgOk("已成功导入" + #outbounds + "个服务器"); 329 | return; 330 | } 331 | 332 | frmV2ray.msgFrown("未导入服务器, 请先复制 vmess:// 或 ss:// 链接!") 333 | } 334 | 335 | return win.loopMessage(); 336 | -------------------------------------------------------------------------------- /lib/config.aardio: -------------------------------------------------------------------------------- 1 | //config 配置文件 2 | import v2ray.config; 3 | import fsys.config; 4 | config = fsys.config( io.appData("/win2ray/") ); 5 | 6 | namespace config { 7 | __appName = "win2ray"; 8 | __loadDefaultOutbounds = function(){ 9 | var serverData = ..string.load("/v2ray-core/win2ray-default-servers.txt") 10 | : $"/v2ray-core/win2ray-default-servers.txt" 11 | 12 | proxy.outbounds = ..v2ray.config.importFromString(..string.removeBom(serverData)); 13 | 14 | ..publish("config.proxy.outbounds.config.changed",) 15 | } 16 | 17 | if(!proxy.outbounds){ 18 | __loadDefaultOutbounds(); 19 | } 20 | } 21 | 22 | if(!config.proxy.mode) config.proxy.mode = "pac"; 23 | 24 | if(!config.core.default){ 25 | config.core.default = { 26 | inbounds={ 27 | { 28 | listen="127.0.0.1"; 29 | port=0; 30 | protocol="socks"; 31 | settings={ 32 | auth="noauth"; 33 | udp=true; 34 | }; 35 | sniffing={ 36 | destOverride={ 37 | "http"; 38 | "tls" 39 | }; 40 | enabled=true 41 | }; 42 | tag="proxy"; 43 | }; 44 | }; 45 | log={ 46 | access=""; 47 | error=""; 48 | loglevel="warning" 49 | }; 50 | outbounds={ 51 | { 52 | tag="proxy" 53 | }; 54 | { 55 | protocol="freedom"; 56 | settings={}; 57 | tag="direct"; 58 | }; 59 | { 60 | protocol="blackhole"; 61 | settings={ 62 | response={ 63 | type="http" 64 | }; 65 | }; 66 | tag="block"; 67 | } 68 | }; 69 | routing={ 70 | domainStrategy="IPIfNonMatch"; 71 | rules={ 72 | { 73 | inboundTag={ 74 | "api" 75 | }; 76 | outboundTag="api"; 77 | type="field"; 78 | } 79 | } 80 | }; 81 | } 82 | } 83 | 84 | 85 | /**intellisense(config) 86 | __appName = 应用程序名 87 | ? = 配置文件名,\n读写配置并序列化为一个表对象,\n表的成员值可以是支持序列化的普通变量,支持table对象\n配置文件在首次使用时自动加载,退出程序时自动保存\n!fsys_table. 88 | end intellisense**/ -------------------------------------------------------------------------------- /lib/style.aardio: -------------------------------------------------------------------------------- 1 | //style 外观样式 2 | 3 | namespace style{ 4 | primaryButton = { 5 | background={ 6 | default=0xFF8FB2B0; 7 | hover=0xFF928BB3; 8 | disabled=0xFFCCCCCC; 9 | } 10 | }; 11 | button = { 12 | background={ 13 | default=0x668FB2B0; 14 | hover=0xFF928BB3; 15 | disabled=0xFFCCCCCC; 16 | } 17 | }; 18 | transButton = { 19 | background={ 20 | default=0; 21 | hover=0xFF928BB3; 22 | disabled=0xFFCCCCCC; 23 | } 24 | }; 25 | checkBox = { 26 | color = { 27 | hover = 0xFFFF0000; 28 | active = 0xFF00FF00; 29 | disabled = 0xEE666666; 30 | } 31 | checked = { 32 | color = { 33 | hover = 0xFFFF0000; 34 | active = 0xFF00FF00; 35 | disabled = 0xEE666666; 36 | } 37 | iconText = '\uF14a'/*_FA_CHECK_SQUARE*/ 38 | } 39 | }; 40 | radio ={ 41 | group = "PinyinMix"; 42 | color = { 43 | hover = 0xFFFF0000; 44 | active = 0xFF00FF00; 45 | } 46 | checked = { 47 | iconText = '\uF058'/*_FA_CHECK_CIRCLE*/ 48 | } 49 | }; 50 | link = { 51 | color = { 52 | default = 0xFF000080; 53 | hover = 0xFFFF0000; 54 | active = 0xFF00FF00; 55 | } 56 | }; 57 | plainButton = { 58 | color = { 59 | default = 0xFF3C3C3C; 60 | hover = 0xFFFF0000; 61 | active = 0xFF00FF00; 62 | disabled = 0xFFCCCCCC; 63 | } 64 | }; 65 | key = { 66 | foreground={ 67 | default = 0x00FFFFFF; 68 | hover= 0xFF8ADBAF; 69 | }; 70 | }; 71 | dropdown = { 72 | background={ 73 | default=0xFF68CC95; 74 | disabled=0xFFC4CCC8; 75 | hover=0xFF4A522F; 76 | }; 77 | color={ 78 | default=0xFF000000; 79 | disabled=0xFF8A8A8A; 80 | hover=0xFFFFFFFF 81 | }; 82 | checked = { 83 | foreground={ 84 | default = 0xFFDB8A8E; 85 | hover= 0xFF8ADBAF; 86 | }; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /lib/v2ray/config.aardio: -------------------------------------------------------------------------------- 1 |  2 | namespace v2ray.config; 3 | 4 | setOutbound = function(outbound){ 5 | import config; 6 | import web.json; 7 | import v2ray.core; 8 | 9 | var current = ..table.clone(config.core.default); 10 | if( ! current.inbounds[1].port ){ 11 | current.inbounds[1].port = ..v2ray.core.getPort(); 12 | } 13 | else{ 14 | ..v2ray.core.setPort(current.inbounds[1].port); 15 | } 16 | 17 | if(outbound.protocol=="vmess"){ 18 | var ob = { 19 | mux={ 20 | concurrency=8; 21 | enabled=true 22 | }; 23 | protocol="vmess"; 24 | settings={ 25 | vnext={ 26 | { 27 | address=outbound.address; 28 | level=outbound.level : 0; 29 | port=outbound.port; 30 | users={ 31 | { 32 | alterId=outbound.alterId : 0; 33 | email=outbound.email : "t@t.tt"; 34 | id=outbound.id; 35 | security=outbound.security; 36 | } 37 | } 38 | } 39 | }; 40 | }; 41 | streamSettings={ 42 | network=outbound.network : "tcp"; 43 | security=outbound.tls; 44 | tlsSettings = outbound.tls ? { 45 | allowInsecure = outbound.tlsAllowInsecure; 46 | serverName = outbound.tlsServerName; 47 | } 48 | }; 49 | tag="proxy" 50 | }; 51 | 52 | if( outbound.network == "ws" ){ 53 | ob.streamSettings.wsSettings = { 54 | path = outbound.path; 55 | headers = outbound.headers; 56 | connectionReuse = true; 57 | } 58 | } 59 | elseif( outbound.network == "http" ){ 60 | ob.streamSettings.httpSettings = { 61 | connectionReuse = true; 62 | path = outbound.path; 63 | host = outbound.host; 64 | } 65 | } 66 | elseif( outbound.network == "tcp" ){ 67 | if( outbound.type == "http" ){ 68 | ob.streamSettings.tcpSettings = { 69 | connectionReuse = true; 70 | header = { 71 | request={ 72 | headers={ 73 | Connection={ 74 | "keep-alive" 75 | }; 76 | Host=outbound.host; 77 | Pragma="no-cache"; 78 | ["Accept-Encoding"]={ 79 | "gzip, deflate" 80 | }; 81 | ["User-Agent"]={ 82 | "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36"; 83 | "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46" 84 | } 85 | }; 86 | method="GET"; 87 | path = outbound.path; 88 | version="1.1" 89 | }; 90 | type="http"; 91 | } 92 | } 93 | } 94 | } 95 | 96 | current.outbounds[1] = ob; 97 | } 98 | elseif(outbound.protocol=="shadowsocks"){ 99 | current.outbounds[1] = { 100 | mux={ 101 | concurrency=-1; 102 | enabled=false 103 | }; 104 | protocol="shadowsocks"; 105 | settings={ 106 | servers={ 107 | { 108 | address=outbound.address; 109 | level=outbound.level : 0; 110 | method=outbound.security; 111 | ota=false; 112 | password=outbound.id; 113 | port=outbound.port; 114 | } 115 | }; 116 | }; 117 | streamSettings={ 118 | network = outbound.network : "tcp"; 119 | }; 120 | tag="proxy" 121 | }; 122 | } 123 | 124 | ..thread.set("v2ray.core.config",web.json.stringify(current)) 125 | } 126 | 127 | getConfigJson = function(){ 128 | return ..thread.get("v2ray.core.config"); 129 | } 130 | 131 | exportToString = function(outbounds){ 132 | import web.json; 133 | import crypt; 134 | 135 | var outString = {}; 136 | for i,outbound in ..table.eachIndex(outbounds){ 137 | if(outbound.protocol == "vmess"){ 138 | var json = ..web.json.stringify({ 139 | v = 2; 140 | add = outbound.address; 141 | aid = outbound.alterId; 142 | id = outbound.id; 143 | port = outbound.port; 144 | net = outbound.net; 145 | type = outbound.type; 146 | path = outbound.path; 147 | host = outbound.host; 148 | tls = outbound.tls; 149 | }) 150 | 151 | var vmess = "vmess://" + ..crypt.encodeBin(json); 152 | ..table.push(outString,vmess); 153 | } 154 | elseif(outbound.protocol == "shadowsocks"){ 155 | var ss = "ss://" + ..crypt.encodeBin( outbound.security + ":" + outbound.id + "@" + outbound.address + ":" + outbound.port) + "#" + outbound.address + ":" + outbound.port; 156 | ..table.push(outString,ss); 157 | } 158 | } 159 | 160 | return ..string.join(outString,'\r\n'); 161 | } 162 | 163 | importFromString = function(str){ 164 | import web.json; 165 | import crypt; 166 | 167 | if(!str){ return; } 168 | 169 | var outbounds = {}; 170 | for(line in ..string.lines(str) ){ 171 | if(line[1]=='#'#){ 172 | continue; 173 | } 174 | 175 | var vmess = ..string.match(line,`vmess\:\/\/([\w=+]+)`); 176 | if( vmess ) { 177 | var json = ..crypt.decodeBin(vmess); 178 | var outbound = ..web.json.tryParse(json); 179 | if(outbound){ 180 | ..table.clear(outbound@._defined); 181 | outbound.protocol = "vmess"; 182 | outbound.address = outbound.add; 183 | outbound.alterId = outbound.aid; 184 | outbound.security = "auto"; 185 | outbound.network = outbound.net : "tcp"; 186 | outbound.net = null; 187 | outbound.add = null; 188 | outbound.aid = null; 189 | outbound.v = null; 190 | ..table.push(outbounds,outbound); 191 | } 192 | 193 | continue; 194 | } 195 | 196 | var ss = ..string.match(line,`ss\:\/\/([\w=+]+)`); 197 | if( ss ) { 198 | var ss = ..crypt.decodeBin(ss); 199 | var method,password,address,port = ..string.match(ss,"^(.+)\:(.+)\@(.+)\:(\d+)") 200 | 201 | if(address && password && port){ 202 | var outbound = { 203 | address = address; 204 | port = tonumber(port); 205 | security = method; 206 | id = password; 207 | network = "tcp"; 208 | protocol = "shadowsocks" 209 | }; 210 | 211 | ..table.push(outbounds,outbound); 212 | } 213 | 214 | continue; 215 | } 216 | 217 | var address,port,id,network,path,tls = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+([\w-]+)\s+(\a+)\s+(\S+)\s+(\a+)") 218 | if(!address) address,port,id,network,path = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+(\S+)\s+(\a+)\s+(\S+)") 219 | if(!address) address,port,id,network = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+(\S+)\s+(\a+)") 220 | 221 | if(address && port && id){ 222 | var outbound = { 223 | address = address; 224 | port = tonumber(port); 225 | id = id; 226 | network = network; 227 | path = path; 228 | tls = tls; 229 | security= "auto"; 230 | protocol = "vmess" 231 | } 232 | 233 | if(outbound.network=="shadowsocks"){ 234 | outbound.network = "tcp"; 235 | outbound.protocol = "shadowsocks"; 236 | outbound.security = outbound.path; 237 | outbound.path = null; 238 | } 239 | ..table.push(outbounds,outbound) 240 | } 241 | } 242 | 243 | return outbounds; 244 | } 245 | 246 | importFromClip = function(){ 247 | import win.clip; 248 | var str = ..win.clip.read(); 249 | if(!str){ return; } 250 | 251 | return importFromString(str); 252 | } -------------------------------------------------------------------------------- /lib/v2ray/core.aardio: -------------------------------------------------------------------------------- 1 | import inet.http; 2 | import zlib.httpFile; 3 | import process.popen; 4 | import wsock.tcp.simpleHttpServer; 5 | import v2ray.config; 6 | import inet.conn; 7 | import config; 8 | import wsock; 9 | 10 | namespace v2ray.core; 11 | 12 | var getV2rayCoreUrl = function(){ 13 | var http = ..inet.http(); 14 | var url = http.location("https://github.com/v2ray/v2ray-core/releases/latest"); 15 | http.close(); 16 | 17 | if(!url)return; 18 | 19 | var tag = ..string.match(url,"[^/]+$") 20 | if(!tag)return; 21 | 22 | return "https://github.com/v2ray/v2ray-core/releases/download/" 23 | + tag + "/v2ray-windows-" + (..process().isWow64() ? "64" : "32") + ".zip" 24 | } 25 | 26 | getPath = function(hwnd){ 27 | var path = ..io.fullpath("/v2ray-core/v2ray.exe"); 28 | if(..io.exist(path)){ 29 | return path; 30 | } 31 | 32 | var path = ..io.appData("/win2ray/core/v2ray.exe"); 33 | if(..io.exist(path)){ 34 | return path; 35 | } 36 | 37 | var url = getV2rayCoreUrl(); 38 | if(!url) return null; 39 | 40 | if( ..zlib.httpFile.download(url,"正在下载 V2ray Core" 41 | ,..io.appData("/win2ray/download/") 42 | ,..io.appData("/win2ray/core/"),,,hwnd) ) 43 | return ..io.exist(path); 44 | } 45 | 46 | var serverMain = ..wsock.tcp.simpleHttpServer.mainThread( 47 | function(response,request,session){ 48 | if(request.path=="/proxy.pac"){ 49 | var pacData = ..string.replace(..string.load(pacPath) 50 | ,"var\s+proxy\s+=\s+%''","var proxy = 'SOCKS 127.0.0.1:"+inboundPort.get()+";'"); 51 | response.contentType = "application/x-ns-proxy-autoconfig"; 52 | response.write(pacData); 53 | } 54 | elseif(request.path=="/config.json"){ 55 | import v2ray.config; 56 | response.contentType = "text/json"; 57 | response.write( v2ray.config.get() ); 58 | } 59 | } 60 | ); 61 | 62 | var pacPath = ..io.appData("/win2ray/proxy.pac.txt"); 63 | if( ! ..io.exist(pacPath) ){ 64 | ..string.save(pacPath,$"/pac.txt" ) 65 | } 66 | 67 | var inboundPort = ..thread.var(); 68 | inboundPort.set( ..wsock.getFreePort() ); 69 | serverMain.threadGlobal = { 70 | inboundPort = inboundPort; 71 | pacPath = pacPath; 72 | } 73 | 74 | getPort = function(){ 75 | return inboundPort.get(); 76 | } 77 | 78 | setPort = function(port){ 79 | inboundPort.set(port); 80 | } 81 | 82 | serverMain.threadNum = 4; 83 | getPacUrl = function(){ 84 | return serverMain.getUrl("/proxy.pac?" + ..time.tick() ); 85 | } 86 | 87 | getConfigUrl = function(){ 88 | return serverMain.getUrl("/config.json"); 89 | } 90 | serverMain.start("127.0.0.1"); 91 | 92 | var prcsv2ray; 93 | restart = function(editor,outbound){ 94 | if(prcsv2ray){ 95 | prcsv2ray.terminate(); 96 | prcsv2ray = null; 97 | } 98 | 99 | var corePath = getPath(editor.hwnd); 100 | if(!corePath) return false,"启动失败,未找到v2ray.exe"; 101 | 102 | ..inet.conn.setProxy(); 103 | ..v2ray.config.setOutbound(outbound); 104 | 105 | var jsonPath = ..io.joinpath(..io.splitpath(corePath).dir,"config.json"); 106 | ..string.save(jsonPath,..v2ray.config.getConfigJson() ) 107 | 108 | prcsv2ray = ..process.popen(corePath,"-format=json","-config=config.json" ); 109 | prcsv2ray.logResponse(editor); 110 | 111 | if(..config.proxy.mode === "pac"){ 112 | ..inet.conn.setProxyAutoConfig(,getPacUrl()) 113 | } 114 | elseif(..config.proxy.mode === "proxy"){ 115 | ..inet.conn.setProxy(,"SOCKS=127.0.0.1:" + inboundPort.get()); 116 | } 117 | else { 118 | ..inet.conn.setProxy(); 119 | } 120 | return true; 121 | } 122 | 123 | stop = function(){ 124 | if(prcsv2ray){ 125 | prcsv2ray.terminate(); 126 | prcsv2ray = null; 127 | } 128 | 129 | if(serverMain){ 130 | serverMain.stop(); 131 | serverMain = null; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /main.aardio: -------------------------------------------------------------------------------- 1 | if(_ARGV.github){ 2 | loadcodex("\forms\main\tools\github.aardio"); 3 | return; 4 | } 5 | elseif(_ARGV.updateTime){ 6 | import time.ntp; 7 | time.ntp.updateSystemTime(); 8 | } 9 | 10 | import fonts.fontAwesome; 11 | import win.ui.atom; 12 | import win.ui; 13 | /*DSG{{*/ 14 | mainForm = win.form(text="win2ray";right=1019;bottom=679;bgcolor=15793151;border="none") 15 | mainForm.add( 16 | caption={cls="bkplus";text="win2ray - 本程序使用 aardio 编写,仅用于技术研究,请勿用于任何不当用途";left=67;top=9;right=727;bottom=27;align="left";color=6052956;dl=1;dt=1;font=LOGFONT(h=-14);z=7}; 17 | custom={cls="custom";left=83;top=40;right=1022;bottom=679;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;z=4}; 18 | logo={cls="bkplus";text='\uF1D9';left=35;top=7;right=64;bottom=32;color=3054125;dl=1;dt=1;font=LOGFONT(h=-18;name='FontAwesome');z=6}; 19 | navBar={cls="bkplus";left=0;top=37;right=83;bottom=681;bgcolor=3442175;db=1;dl=1;dt=1;z=1}; 20 | navJsonConfig={cls="plus";text="配置";left=0;top=132;right=85;bottom=212;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF0F6';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=5}; 21 | navStart={cls="plus";text="首页";left=0;top=48;right=85;bottom=128;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF015';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=3}; 22 | navTools={cls="plus";text="工具";left=0;top=216;right=85;bottom=296;bkBottom=3;bkLeft=7;bkRight=8;bkTop=2;border={color=-65536};color=16777215;dl=1;dt=1;font=LOGFONT(h=-13);iconStyle={font=LOGFONT(h=-37;name='FontAwesome');padding={bottom=20}};iconText='\uF0AD';notify=1;textPadding={bottom=10};valign="bottom";x=0.5;y=0.2;z=8}; 23 | titleBar={cls="bkplus";left=0;top=0;right=1022;bottom=38;bgcolor=8036607;dl=1;dr=1;dt=1;forecolor=16777215;linearGradient=180;z=2} 24 | ) 25 | /*}}*/ 26 | 27 | var atom,hwnd = mainForm.atom("DFA5667E-1D8C-49C0-8918-C6FEC2DECCF8"); 28 | if(!atom){ 29 | win.showForeground(hwnd); 30 | win.quitMessage(); 31 | return; 32 | } 33 | 34 | import v2ray.core; 35 | if(!v2ray.core.getPath()) { 36 | mainForm.close(); 37 | return; 38 | } 39 | 40 | import win.ui.simpleWindow; 41 | win.ui.simpleWindow( mainForm ); 42 | 43 | import win.dlg.message; 44 | win.dlg.message.install(); 45 | 46 | import win.ui.tabs; 47 | var tbs = win.ui.tabs( 48 | mainForm.navStart, 49 | mainForm.navJsonConfig, 50 | mainForm.navTools 51 | ); 52 | 53 | tbs.skin({ 54 | background={ 55 | active=0xFFFFFFFF; 56 | default=0x00FFFFFF; 57 | hover=0x38FFFFFF 58 | }; 59 | color={ 60 | default=0xFFFFFFFF; 61 | }; 62 | checked={ 63 | background={default=0xFFFFFFFF;}; 64 | color={default=0xff86a543;}; 65 | } 66 | }) 67 | 68 | tbs.loadForm(1,"\forms\main\v2ray.aardio" ); 69 | tbs.loadForm(2,"\forms\main\json.aardio" ); 70 | tbs.loadForm(3,"\forms\main\tools\tools.aardio"); 71 | 72 | tbs.selIndex = 1; 73 | 74 | import win.util.tray; 75 | mainForm.onMinimize = function(lParam){ 76 | mainForm.tray = win.util.tray(mainForm) 77 | mainForm.show(false); 78 | return true; 79 | } 80 | 81 | import inet.conn; 82 | mainForm.onDestroy = function(){ 83 | mainForm.tray.delete(); 84 | inet.conn.setProxy(); 85 | } 86 | 87 | mainForm.onClose = function(hwnd,message,wParam,lParam){ 88 | mainForm.onMinimize(); 89 | return true; 90 | } 91 | 92 | import win.ui.menu; 93 | mainForm.wndproc = { 94 | [0xACCF/*_WM_TRAYMESSAGE*/ ] = function(hwnd,message,wParam,lParam){ 95 | if( lParam = 0x205/*_WM_RBUTTONUP*/ ){ 96 | win.setForeground(mainForm.hwnd) 97 | mainForm.popmenu = win.ui.popmenu(mainForm); 98 | mainForm.popmenu.add('自动切换到最快的服务器',function(id){ 99 | publish("config.proxy.outbounds.changed",) 100 | }); 101 | mainForm.popmenu.add(); 102 | 103 | import inet.conn; 104 | import v2ray.core; 105 | var id = mainForm.popmenu.add('使用PAC自动代理',function(id){ 106 | config.proxy.mode = "pac"; 107 | inet.conn.setProxyAutoConfig(,v2ray.core.getPacUrl() ); 108 | publish("config.proxy.mode.changed"); 109 | }); 110 | mainForm.popmenu.check(id,config.proxy.mode=="pac",0/*_MF_BYCOMMAND*/); 111 | 112 | var id = mainForm.popmenu.add('使用全局代理',function(id){ 113 | config.proxy.mode = "proxy"; 114 | inet.conn.setProxy(,"SOCKS=127.0.0.1:"+v2ray.core.getPort()); 115 | publish("config.proxy.mode.changed"); 116 | }); 117 | mainForm.popmenu.check(id,config.proxy.mode=="proxy",0/*_MF_BYCOMMAND*/); 118 | 119 | var id = mainForm.popmenu.add('不使用代理',function(id){ 120 | config.proxy.mode = "direct"; 121 | inet.conn.setProxy(); 122 | publish("config.proxy.mode.changed"); 123 | }); 124 | mainForm.popmenu.check(id,config.proxy.mode=="direct",0/*_MF_BYCOMMAND*/); 125 | 126 | mainForm.popmenu.add(); 127 | 128 | mainForm.popmenu.add('退出',function(id){ 129 | mainForm.onClose = null; 130 | mainForm.close() 131 | }); 132 | 133 | var pt = ::POINT(); 134 | ::User32.GetCursorPos(pt); 135 | mainForm.popmenu.popup(pt.x,pt.y,true) 136 | } 137 | elseif( lParam = 0x203/*_WM_LBUTTONDBLCLK*/) { 138 | mainForm.show(); 139 | win.setForeground(mainForm.hwnd); 140 | } 141 | } 142 | } 143 | 144 | mainForm.show(); 145 | return win.loopMessage(); 146 | -------------------------------------------------------------------------------- /screenshots/config.json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/screenshots/config.json.png -------------------------------------------------------------------------------- /screenshots/config.txt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/screenshots/config.txt.png -------------------------------------------------------------------------------- /screenshots/config.vmess.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/screenshots/config.vmess.png -------------------------------------------------------------------------------- /screenshots/win2ray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/screenshots/win2ray.png -------------------------------------------------------------------------------- /v2ray-core/v2ctl.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/v2ray-core/v2ctl.exe -------------------------------------------------------------------------------- /v2ray-core/v2ray.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/v2ray-core/v2ray.exe -------------------------------------------------------------------------------- /v2ray-core/win2ray-default-servers.txt: -------------------------------------------------------------------------------- 1 | # 号开头为注释行。 2 | # 每行一个服务器配置,也可以每行一个vmess://或ss://链接 3 | # vmess 服务器每行字段依次为 address port id network path tls 4 | # ss 服务器每行字段依次为 address port password shadowsocks method 5 | # 免费服务器可可以直接复制https://www.youneed.win/free-v2ray/(需要开全局代理) 页面所有账号然后粘贴到下面即可。 6 | # 付费服务器目前 justmysocks3.net 靠谱一些,一个账号可以提供多个服务器域名,并且可以自动换IP,按月购买也随时可以取消。 7 | # 下面以 justmysocks3.net 为例: 8 | 9 | # c33s3.jamjams.net 80 ********-****-****-****-*********** tcp 10 | # c33s4.jamjams.net 80 ********-****-****-****-*********** tcp 11 | # c33s5.jamjams.net 80 ********-****-****-****-*********** tcp 12 | # c33s801.jamjams.net 80 ********-****-****-****-*********** tcp 13 | # c33s1.jamjams.net 80 ******** shadowsocks aes-256-gcm 14 | # c33s2.jamjams.net 80 ******** shadowsocks aes-256-gcm 15 | -------------------------------------------------------------------------------- /win2ray.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/riba2534/win2ray/c886a242a09df1b422d69900d140ffe49172e2af/win2ray.exe --------------------------------------------------------------------------------