├── .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 | 
12 |
13 | 批量导入各种格式的服务器配置,支持json、vmess链接、ss链接、文本表格格式服务器列表等。
14 | 可选在 ["/v2ray-core/win2ray-default-servers.txt"](./v2ray-core/win2ray-default-servers.txt) 文件中添加默认服务器列表(生成EXE后默认配置自动嵌入到EXE文件,可选删除该文件,也可以继续使用该文件覆盖EXE自带的默认服务器列表)。
15 |
16 | 
17 |
18 | 
19 |
20 | 
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------