├── .build
├── default.Manifest.xml
├── default.init.aardio
└── default.main.aardio
├── .gitignore
├── LICENSE
├── README.md
├── app.ico
├── default.aproj
├── forms
└── main
│ ├── json.aardio
│ ├── pac.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
├── pac.jpg
└── win2ray.png
├── v2ray-core
├── LICENSE
├── v2ctl.exe
├── v2ray.exe
└── win2ray-default-servers.json
└── 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 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # win2ray
2 | 简洁稳定的 V2Ray(兼容Shadowsocks) Windows 客户端,
3 | 支持自动检测可用的代理服务器、断线自动更换服务器。本程序使用 [aardio](http://www.aardio.com) 编写,不需要.Net运行库,生成的EXE非常小。
4 |
5 | win2ray 可自动并选择响应最快的代理服务器尝试连接,连接成功立即模拟浏览器检测访问国外网站是否异常,异常则自动更换代理服务器:
6 | 
7 |
8 | 可导入导出各种格式的服务器配置,支持json、vmess链接、ss链接、文本表格格式服务器列表、订阅链接等。
9 | 可选在 ["/v2ray-core/win2ray-default-servers.json"](./v2ray-core/win2ray-default-servers.json) 文件中添加默认服务器配置(生成EXE后默认配置自动嵌入到EXE文件,可选删除该文件,也可以继续使用该文件覆盖EXE自带的默认服务器列表)。
10 |
11 | 
12 |
13 | 
14 |
15 | 软件首次运行时会在当前目录查找 "./v2ray-core/v2ray.exe"
16 | 发行文件仅需要 "./win2ray.exe",可选带上 "./v2ray-core/" 目录( 如果没有找到会自动到v2ray官网下载,不过没有代理服务器下载有时候非常慢 )。
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/app.ico
--------------------------------------------------------------------------------
/default.aproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/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 : ..table.array();
67 | }
68 | else {
69 | var outbounds = v2ray.config.importFromString(winform.editOutbounds.text);
70 | config.proxy.outbounds = outbounds : ..table.array();
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 strEditBounds = string.trim(winform.editOutbounds.text);
107 | var menu = {
108 | { /*---分隔线---*/ };
109 | { "自剪贴板批量导入vmess、ss链接、或订阅源";
110 | function(id){
111 |
112 | var outbounds = v2ray.config.importFromClip();
113 | if(#outbounds){
114 | var json = strEditBounds;
115 | if( (!#json) || ..string.match(json,"%\[\]")){
116 | var cfg,err = ..table.array();
117 | if(#json){
118 | cfg,err= web.json.tryParse(strEditBounds);
119 | if(!cfg){
120 | winform.editOutbounds.showErrorTip(,string.concat("当前配置存在JSON语法错误 ",err));
121 | return;
122 | }
123 | }
124 |
125 | ..table.append(cfg,outbounds);
126 | winform.editOutbounds.text = ..web.json.stringify(cfg,true);
127 | }
128 | else {
129 | var str = v2ray.config.exportToString(outbounds);
130 | if(#strEditBounds){
131 | winform.editOutbounds.text = strEditBounds+ '\r\n' + str;
132 | }
133 | else {
134 | winform.editOutbounds.text = str;
135 | }
136 | }
137 |
138 | winform.msgOk("已成功导入" + #outbounds + "个服务器");
139 | winform.editOutbounds.modified = true;
140 | winform.editOutbounds.setFocus();
141 | return;
142 | }
143 |
144 | winform.msgFrown("未导入服务器, 请先复制订阅源、或vmess、ss链接!")
145 | }
146 | };
147 | }
148 |
149 | if( (!#strEditBounds) || ..string.match(strEditBounds,"%\[\]")){
150 | menu[3] = { "更新订阅源";
151 | function(id){
152 | var cfg,err = ..table.array();
153 |
154 | var json = strEditBounds;
155 | if(#json){
156 | cfg,err = web.json.tryParse(strEditBounds);
157 | if(!cfg){
158 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err));
159 | return;
160 | }
161 | }
162 |
163 | var subscribeUrls = {}
164 | for(i=#cfg;1;-1){
165 | var outbound = cfg[i]
166 | if(outbound.subscribeUrl){
167 | subscribeUrls[outbound.subscribeUrl] = true;
168 | }
169 | }
170 |
171 | if(!table.count(subscribeUrls)){
172 | import win.clip;
173 | var clibStr = win.clip.read();
174 | if( ..string.startWith(clibStr,"http://") || ..string.startWith(clibStr,"https://") ){
175 | subscribeUrls[clibStr] = true;
176 | }
177 | else {
178 | winform.msgWarn('当前配置不包含来自订阅源的服务器,\n请先复制订阅源网址到剪贴板!');
179 | return;
180 | }
181 | }
182 |
183 | var count = 0;
184 | for(url,v in subscribeUrls){
185 | var outbounds = v2ray.config.importFromString(url);
186 | if(#outbounds){
187 | for(i=#cfg;1;-1){
188 | var outbound = cfg[i]
189 | if(outbound.subscribeUrl==url){
190 | ..table.remove( cfg,i );
191 | }
192 | }
193 |
194 | count = count + #outbounds;
195 | ..table.append(cfg,outbounds);
196 | }
197 | }
198 |
199 | winform.editOutbounds.text = ..web.json.stringify(cfg,true);
200 |
201 | winform.msgOk("已成功刷新" + count + "个服务器");
202 | winform.editOutbounds.modified = true;
203 | winform.editOutbounds.setFocus();
204 | return;
205 | }
206 | };
207 | }
208 |
209 | if(..string.match(strEditBounds,"%\[\]")){
210 | menu[4] = {}
211 | menu[5] = { "转换为 vmess:// 或 ss:// 链接";
212 | function(id){
213 | var cfg,err = web.json.tryParse(strEditBounds);
214 | if(!cfg){
215 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err));
216 | return;
217 | }
218 |
219 | var str = v2ray.config.exportToString(cfg);
220 | if(str){
221 | winform.editOutbounds.text = str;
222 | winform.editOutbounds.modified = true;
223 | }
224 | }
225 | };
226 | menu[6] = { "转换为 Base64 订阅源";
227 | function(id){
228 | var cfg,err = web.json.tryParse(strEditBounds);
229 | if(!cfg){
230 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err));
231 | return;
232 | }
233 |
234 | var str = v2ray.config.exportToString(cfg);
235 | if(str){
236 | import crypt;
237 | winform.editOutbounds.text = ..crypt.encodeBin(str);
238 | winform.editOutbounds.modified = true;
239 | }
240 | }
241 | };
242 | menu[7] = { "转换为文本格式";
243 | function(id){
244 | var cfg,err = web.json.tryParse(strEditBounds);
245 | if(!cfg){
246 | winform.editOutbounds.showErrorTip(,string.concat("JSON语法错误 ",err));
247 | return;
248 | }
249 |
250 | var outstr = {};
251 | for i,outbound in table.eachIndex(cfg){
252 | if(outbound.protocol != "shadowsocks"){
253 | var path = outbound.path;
254 | if( outbound.host){
255 | path = ( (#outbound.type && outbound.type!="none") ? outbound.type : outbound.network : "")
256 | + "://" + outbound.host ++ path;
257 | }
258 |
259 | table.push(outstr, string.concat( outbound.address,'\t'
260 | ,outbound.port,'\t'
261 | ,outbound.id,,'\t'
262 | ,outbound.network,'\t'
263 | ,path,'\t'
264 | ,outbound.tls ) );
265 | }
266 | else {
267 | table.push(outstr, string.concat( outbound.address,'\t'
268 | ,outbound.port,'\t'
269 | ,outbound.id,,'\t'
270 | ,'shadowsocks\t'
271 | ,outbound.security) );
272 | }
273 | }
274 |
275 | winform.editOutbounds.text = string.join(outstr,'\r\n');
276 | winform.editOutbounds.modified = true;
277 | }
278 | };
279 | }
280 | elseif( #strEditBounds ) {
281 | menu[3] = {}
282 |
283 | menu[4] = { "转换为 JSON";
284 | function(id){
285 | import web.json;
286 | var outbounds = v2ray.config.importFromString(strEditBounds);
287 | if(outbounds){
288 | winform.editOutbounds.text = web.json.stringify(outbounds,true);
289 | winform.editOutbounds.modified = true;
290 | }
291 | }
292 | };
293 | }
294 |
295 | table.push(menu,{ /*---分隔线---*/ });
296 | if(winform.editOutbounds.modified){
297 | table.push(menu,{ "恢复为当前应用的服务器配置(JSON)";
298 | function(id){
299 | winform.editOutbounds.text = web.json.stringify(
300 | config.proxy.outbounds,true
301 | )
302 | winform.editOutbounds.modified = false;
303 | }
304 | });
305 | }
306 |
307 | table.push(menu,{ "恢复为默认服务器配置(JSON)";
308 | function(id){
309 | ..config.__loadDefaultOutbounds();
310 | publish("config.proxy.outbounds.changed",cfg);
311 | }
312 | });
313 |
314 | return menu;
315 | }
316 | })
317 |
318 | subscribe("config.proxy.outbounds.config.changed",function(){
319 | if(winform.editOutbounds.modified){
320 | return;
321 | }
322 |
323 | winform.editOutbounds.text = web.json.stringify(
324 | config.proxy.outbounds,true
325 | )
326 |
327 | winform.editOutbounds.modified = false;
328 | } )
329 |
330 | winform.editOutbounds.text = #config.proxy.outbounds ? web.json.stringify(
331 | config.proxy.outbounds ,true
332 | ) : "[]"
333 | winform.editOutbounds.modified = false;
334 |
335 | winform.editCoreConfig.text = web.json.stringify(
336 | config.core.default,true
337 | )
338 |
339 | winform.enableDpiScaling();
340 | winform.show();
341 | win.loopMessage();
342 | return winform;
--------------------------------------------------------------------------------
/forms/main/pac.aardio:
--------------------------------------------------------------------------------
1 |
2 | import win.ui;
3 | import win.ui.atom;
4 | import fonts.fontAwesome;
5 | /*DSG{{*/
6 | var winform = win.form(text="win2ray - 代理自动配置文件(PAC)";right=912;bottom=802;bgcolor=16777215)
7 | winform.add(
8 | btnReset={cls="plus";text="恢复PAC";left=609;top=763;right=741;bottom=794;align="left";bgcolor=14935259;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=6};
9 | btnSave={cls="plus";text="保存PAC";left=751;top=763;right=883;bottom=794;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};
10 | btnUpdate={cls="plus";text="同步到网络最新PAC";left=402;top=763;right=599;bottom=794;align="left";bgcolor=14935259;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=22}};iconText='\uF1C4';notify=1;textPadding={left=40};z=4};
11 | editPacDirect={cls="richedit";left=9;top=37;right=902;bottom=743;db=1;dl=1;dr=1;dt=1;edge=1;hidesel=false;hscroll=1;multiline=1;vscroll=1;z=1};
12 | editPacProxy={cls="richedit";left=9;top=37;right=902;bottom=751;db=1;dl=1;dr=1;dt=1;edge=1;hidesel=false;hscroll=1;multiline=1;vscroll=1;z=2};
13 | lbTip={cls="plus";text="以下域名通过代理连接。";left=11;top=9;right=899;bottom=35;align="left";color=3947580;dl=1;dr=1;dt=1;font=LOGFONT(h=-13);notify=1;transparent=1;z=9};
14 | navDirect={cls="plus";text="直连域名( JSON )";left=184;top=750;right=315;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=5};
15 | navProxy={cls="plus";text="代理域名( JSON )";left=53;top=750;right=184;bottom=782;border={top=1;color=-16744448};db=1;dl=1;z=3};
16 | 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=8};
17 | plus={cls="plus";left=9;top=750;right=53;bottom=751;border={color=-16744448};db=1;dl=1;forecolor=32768;z=10}
18 | )
19 | /*}}*/
20 |
21 | import config;
22 | import web.json;
23 | import win.ui.tabs;
24 | var tbs = win.ui.tabs(winform.navProxy,winform.navDirect,winform.nav06,winform.nav091,winform.navZhengMa,winform.navTxt)
25 | tbs.margin = 0;
26 |
27 | tbs.skin({
28 | foreground={
29 | active=0xFFFFFFFF;
30 | default=0x00FFFFFF;
31 | hover=0xFFCCCCCC;
32 | };
33 | checked={
34 | foreground={
35 | default=0x00FFFFFF;
36 | };
37 | border = {
38 | default = {left=1;right=1;bottom=1;color=0xFF008000}
39 | };
40 | }
41 | });
42 |
43 | tbs.onSelchange = function(idx,strip,form){
44 | if(idx==1){
45 | winform.currentEditPac = winform.editPacProxy;
46 | winform.editPacProxy.hide = false;
47 | winform.editPacDirect.hide = true;
48 | winform.lbTip.text = `以下域名通过代理连接:`
49 | }
50 | else {
51 | winform.currentEditPac = winform.editPacDirect;
52 | winform.editPacProxy.hide = true;
53 | winform.editPacDirect.hide = false;
54 | winform.lbTip.text = `以下域名不使用代理: `
55 | }
56 | }
57 | tbs.selIndex = 1;
58 |
59 | import win.dlg.message;
60 | win.dlg.message.install();
61 |
62 | winform.loadPacToEdit = function(str){
63 | var rules = string.match(str,"var\s+rules\s*=\s*(%\[\])")
64 | if(!rules) return winform.msgErr("PAC文件格式错误");
65 |
66 | rules = web.json.parse(rules);
67 | if(!(rules && table.isArray(rules) && type(rules[1][1])==type.table)) return winform.msgErr("PAC文件格式错误");
68 |
69 | import win.clip;
70 |
71 |
72 | var proxy,direct = table.array(),table.array()
73 | for(i=1;#rules){
74 | win.clip.write(table.tostring(rules[i][1]))
75 | table.append(direct,rules[i][1]);
76 | table.append(proxy,rules[i][2]);
77 | }
78 |
79 | winform.editPacProxy.text = web.json.stringify(proxy,true)
80 | winform.editPacDirect.text = web.json.stringify(direct,true)
81 | }
82 |
83 | import string.conv;
84 | winform.savePacToFile = function(){
85 | var proxy = web.json.tryParse(string.conv.fromWide(winform.editPacProxy.text))
86 | var direct = web.json.tryParse(string.conv.fromWide(winform.editPacDirect.text))
87 | if(!(proxy)) return winform.msgErr("代理域名配置格式错误");
88 | if(!(direct)) return winform.msgErr("直连域名配置格式错误");
89 |
90 | str = string.replace($"/pac.txt","var\s+rules\s*=\s*%\[\]","var rules = " + web.json.stringify({{direct;proxy}},true))
91 | string.save(io.appData("/win2ray-v2/proxy.pac.txt"),str );
92 | }
93 |
94 | import config;
95 | import style;
96 | winform.btnSave.skin(style.primaryButton);
97 | winform.btnUpdate.skin(style.button);
98 | winform.btnReset.skin(style.button);
99 | winform.lbTip.skin(style.link);
100 |
101 | winform.btnUpdate.oncommand = function(id,event){
102 | winform.btnUpdate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'};
103 |
104 | thread.invoke(
105 | function(winform){
106 | import crypt;
107 | import web.rest.jsonLiteClient;
108 |
109 | var http = web.rest.jsonLiteClient();
110 | var github = http.api("https://api.github.com");
111 |
112 | var result = github.repos["petronny"]["gfwlist2pac"].contents["gfwlist.pac"].get();
113 | if(result[["content"]] && result[["encoding"]]=="base64"){
114 | winform.loadPacToEdit( crypt.decodeBin(result[["content"]]) );
115 | winform.editPacDirect.modified = true;
116 | winform.btnSave.disabled = false;
117 | winform.btnReset.disabled = false;
118 | winform.msgOk("PAC已同步到最新版本,请点击「保存PAC」按钮");
119 | }
120 | else {
121 | winform.msgFrown("PAC更新失败,建议开启全局代理后重试。")
122 | }
123 | winform.btnUpdate.disabledText = null;
124 | },winform
125 | )
126 | }
127 |
128 |
129 | winform.btnSave.oncommand = function(id,event){
130 | winform.btnSave.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'};
131 |
132 | thread.invoke(
133 | function(winform){
134 | winform.savePacToFile();
135 | winform.updateProxy();
136 |
137 | sleep(500);
138 | winform.btnSave.disabledText = null;
139 | winform.btnSave.disabled = true;
140 | winform.btnReset.disabled = true;
141 | winform.msgOk("已保存PAC文件")
142 | },winform
143 | )
144 | }
145 |
146 | winform.btnReset.oncommand = function(id,event){
147 | winform.btnReset.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'};
148 |
149 | thread.invoke(
150 | function(winform){
151 | var pacPath = io.appData("/win2ray-v2/proxy.pac.txt");
152 | var str = io.exist(pacPath) ? string.load(pacPath) || $"/pac.txt";
153 | if(str) winform.loadPacToEdit(str);
154 |
155 | sleep(500);
156 | winform.btnReset.disabledText = null;
157 | winform.btnSave.disabled = true;
158 | winform.btnReset.disabled = true;
159 | winform.msgOk("已恢复到当前PAC配置")
160 | },winform
161 | )
162 | }
163 |
164 | import config;
165 | import v2ray.core;
166 | winform.updateProxy = function(){
167 | if(config.proxy.mode === "pac"){
168 | inet.conn.setProxy(,"SOCKS=127.0.0.1:"+v2ray.core.getPort());
169 | inet.conn.setProxyAutoConfig(,v2ray.core.getPacUrl() )
170 | }
171 | elseif(..config.proxy.mode === "proxy"){
172 | inet.conn.setProxyAutoConfig(,v2ray.core.getPacUrl() )
173 | inet.conn.setProxy(,"SOCKS=127.0.0.1:"+v2ray.core.getPort());
174 | }
175 | }
176 |
177 | var pacPath = io.appData("/win2ray-v2/proxy.pac.txt");
178 | var str = io.exist(pacPath) ? string.load(pacPath) || $"/pac.txt";
179 | if(str) winform.loadPacToEdit(str);
180 |
181 | winform.editPacProxy.modified = false;
182 | winform.editPacDirect.modified = false;
183 | winform.btnSave.disabled = true;
184 | winform.btnReset.disabled = true;
185 |
186 | winform.editPacDirect.limit = -1;
187 | winform.editPacDirect.onChange = function(){
188 | winform.btnSave.disabled = false;
189 | winform.btnReset.disabled = false;
190 | }
191 |
192 | winform.editPacProxy.limit = -1;
193 | winform.editPacProxy.onChange = function(){
194 | winform.btnSave.disabled = false;
195 | winform.btnReset.disabled = false;
196 | }
197 |
198 | import process;
199 | winform.lbTip.oncommand = function(id,event){
200 | process.openUrl("https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file")
201 | }
202 |
203 | import win.dlg.findReplace;
204 | var findDlgDirect = win.dlg.findReplace(winform);
205 |
206 | findDlgDirect.onSearch = function(findWhat,down,matchCase,wholeWord){
207 | winform.currentEditPac.findText(findWhat,findDlgDirect.flags);
208 | }
209 |
210 | findDlgDirect.onReplace = function(findWhat,replaceWith,down,matchCase,wholeWord){
211 | winform.currentEditPac.replaceText(findWhat,replaceWith,findDlgDirect.flags);
212 | }
213 |
214 | findDlgDirect.onReplaceAll = function(findWhat,replaceWith,down,matchCase,wholeWord){
215 | winform.currentEditPac.replaceAll(findWhat,replaceWith,findDlgDirect.flags)
216 | }
217 |
218 | winform.editPacDirect.enablePopMenu(function(){
219 | var items = {
220 | { "查找 Ctrl + F";
221 | function(id){
222 | findDlgDirect.find(winform.editPacDirect.selText)
223 | }
224 | };
225 | { "替换 Ctrl + H";
226 | function(id){
227 | findDlgDirect.replace(winform.editPacDirect.selText);
228 | }
229 | }
230 | }
231 | return items;
232 | });
233 |
234 | winform.editPacProxy.enablePopMenu(function(){
235 | var items = {
236 | { "查找 Ctrl + F";
237 | function(id){
238 | findDlgDirect.find(winform.editPacProxy.selText)
239 | }
240 | };
241 | { "替换 Ctrl + H";
242 | function(id){
243 | findDlgDirect.replace(winform.editPacProxy.selText);
244 | }
245 | }
246 | }
247 | return items;
248 | });
249 |
250 |
251 | import win.ui.accelerator;
252 | var accelerator = win.ui.accelerator({
253 |
254 | {
255 | ctrl = true; vkey = 'F'#;
256 | oncommand = function() findDlgDirect.find(winform.currentEditPac.selText);
257 | };
258 |
259 | {
260 | ctrl = true; vkey = 'H'#;
261 | oncommand = function() findDlgDirect.replace(winform.currentEditPac.selText);
262 | };
263 |
264 | },winform );
265 |
266 | winform.enableDpiScaling();
267 | winform.show();
268 | win.loopMessage();
269 |
270 | 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 / 并更新图像等服务器IP';left=77;top=158;right=563;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 | var githubIps = {
157 | ["www.github.com"] = ip;
158 | ["github.com"] = ip;
159 | }
160 |
161 | import web.rest.jsonLiteClient;
162 | var http = web.rest.jsonLiteClient();
163 | var ipApi = http.api("http://ip-api.com/json");
164 | var data = ipApi["raw.githubusercontent.com"].get();
165 | if(data[["query"]]){
166 | githubIps["raw.github.com"] = data[["query"]];
167 | githubIps["assets-cdn.github.com"] = data[["query"]];
168 | githubIps["raw.githubusercontent.com"] = data[["query"]];
169 | githubIps["gist.githubusercontent.com"] = data[["query"]];
170 | githubIps["cloud.githubusercontent.com"] = data[["query"]];
171 | githubIps["camo.githubusercontent.com"] = data[["query"]];
172 | githubIps["avatars0.githubusercontent.com"] = data[["query"]];
173 | githubIps["avatars1.githubusercontent.com"] = data[["query"]];
174 | githubIps["avatars2.githubusercontent.com"] = data[["query"]];
175 | githubIps["avatars3.githubusercontent.com"] = data[["query"]];
176 | githubIps["avatars4.githubusercontent.com"] = data[["query"]];
177 | githubIps["avatars5.githubusercontent.com"] = data[["query"]];
178 | githubIps["avatars6.githubusercontent.com"] = data[["query"]];
179 | githubIps["avatars7.githubusercontent.com"] = data[["query"]];
180 | githubIps["avatars8.githubusercontent.com"] = data[["query"]];
181 | githubIps["marketplace-screenshots.githubusercontent.com"] = data[["query"]];
182 | githubIps["repository-images.githubusercontent.com"] = data[["query"]];
183 | githubIps["user-images.githubusercontent.com"] = data[["query"]];
184 | githubIps["desktop.githubusercontent.com"] = data[["query"]];
185 | }
186 |
187 | fsys.hosts.ownCacls();
188 | fsys.hosts.update(githubIps);
189 |
190 | win.delay(1000);
191 | winform.editIpCurrent.text = wsock.getIp("www.github.com");
192 | winform.plusUpdateDns.disabledText = null;
193 |
194 | if( ip != winform.editIpCurrent.text ){
195 | winform.msgboxErr("修改hosts文件失败,如果hosts文件被其他软件锁定时请先解除锁定,也可以搜索网上教程试试设置文件权限")
196 | }
197 | }
198 |
199 | winform.plusExploreHosts.skin(
200 | background = {
201 | hover = "/res/images/btn-hover.png";
202 | focus = "/res/images/btn-focus.jpg";
203 | active = "/res/images/btn-active.png";
204 | disabled = "/res/images/btn-disabled.png";
205 | }
206 | )
207 | winform.plusExploreHosts.oncommand = function(id,event){
208 | import process;
209 | process.exploreSelect(fsys.hosts.path)
210 | }
211 |
212 | winform.plusUpdateDns.skin({
213 | background={
214 | default=0xFF93C89E;
215 | hover=0xFF928BB3
216 | }
217 | })
218 |
219 | winform.plusUpdateIps.skin({
220 | background={
221 | default=0xFF93C89E;
222 | hover=0xFF928BB3
223 | }
224 | })
225 |
226 | winform.plusExploreHosts.skin({
227 | background={
228 | default=0xFF93C89E;
229 | hover=0xFF928BB3
230 | }
231 | })
232 |
233 | import win.ui.simpleWindow2;
234 | win.ui.simpleWindow2(winform);
235 |
236 | winform.enableDpiScaling();
237 | winform.show()
238 | winform.plusUpdateIps.oncommand();
239 |
240 | win.loopMessage();
241 |
--------------------------------------------------------------------------------
/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=287;right=295;bottom=329;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 | btnDnsFlush={cls="plus";text="清空DNS缓存";left=44;top=106;right=430;bottom=148;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='\uF021';notify=1;textPadding={left=50};z=5};
8 | btnGitHub={cls="plus";text="github 网速优化";left=44;top=227;right=280;bottom=269;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};
9 | 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};
10 | btnYoutube={cls="plus";text="youtube 视频下载工具";left=44;top=167;right=280;bottom=209;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}
11 | )
12 | /*}}*/
13 |
14 | import style;
15 | winform.btnYoutube.skin(style.plainButton)
16 |
17 | var frmYoutube;
18 | winform.btnYoutube.oncommand = function(id,event){
19 | if(frmYoutube&&win.isWindow(frmYoutube.hwnd)){
20 | if(win.isIconic(frmYoutube.hwnd)){
21 | frmYoutube.show(9/*_SW_RESTORE*/);
22 | }
23 |
24 | frmYoutube.show();
25 | return;
26 | }
27 |
28 | frmYoutube = winform.loadForm("\forms\main\tools\youtube.aardio");
29 | frmYoutube.show();
30 | }
31 |
32 | import process;
33 | winform.btnGitHub.skin(style.plainButton)
34 | winform.btnGitHub.oncommand = function(id,event){
35 | if(_STUDIO_INVOKED){
36 | winform.msgboxErr("请在发布后运行此功能");
37 | return;
38 | }
39 |
40 | process.execute(io._exepath,"/github","runas");
41 | }
42 |
43 | winform.btnAardio.skin(style.plainButton)
44 | winform.btnAardio.oncommand = function(id,event){
45 | process.openUrl("http://www.aardio.com")
46 | }
47 |
48 | winform.btnUpdateSystemTime.skin(style.plainButton)
49 | winform.btnUpdateSystemTime.oncommand = function(id,event){
50 | if(_STUDIO_INVOKED){
51 | winform.msgboxErr("请在发布后运行此功能");
52 | return;
53 | }
54 |
55 | winform.btnUpdateSystemTime.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
56 | if( process.executeWait(io._exepath,"/updateTime","runas") ){
57 | winform.btnUpdateSystemTime.disabledText = null;
58 | winform.btnUpdateSystemTime.text = '时间已同步'
59 | winform.setTimeout(
60 | function(){
61 | winform.btnUpdateSystemTime.text = '同步系统时间( 修正 v2ray 连接报错 )'
62 | },2000)
63 | }
64 | else {
65 | winform.btnUpdateSystemTime.disabledText = null;
66 | }
67 | }
68 |
69 | winform.btnDnsFlush.skin(style.plainButton)
70 | winform.btnDnsFlush.oncommand = function(id,event){
71 | winform.btnDnsFlush.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
72 |
73 | import process.popen;
74 | var prcs = process.popen(,"ipconfig /flushdns");
75 | var str = prcs.read(-1)
76 |
77 | var dnsapi = ..raw.loadDll("dnsapi.dll");
78 | dnsapi.DnsFlushResolverCacheB();
79 |
80 | winform.msgInfo(str);
81 | winform.btnDnsFlush.disabledText = null;
82 | }
83 |
84 | winform.enableDpiScaling();
85 | winform.show();
86 | 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.enableDpiScaling();
94 | winform.show();
95 | 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 | btnEditPac={cls="plus";text="编辑PAC";left=346;top=364;right=452;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};
8 | btnImportServerFromClipBd={cls="plus";text="批量导入链接";left=459;top=364;right=592;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};
9 | 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};
10 | chkAutoTest={cls="plus";text="断线重连";left=598;top=364;right=701;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='\uF0C8';notify=1;textPadding={left=30};z=9};
11 | 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};
12 | listview={cls="listview";left=4;top=5;right=954;bottom=358;db=1;dl=1;dr=1;dt=1;edge=1;fullRow=1;gridLines=1;z=1};
13 | radioProxy={cls="radiobutton";text="全局代理";left=129;top=370;right=226;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=4};
14 | radioProxyDirect={cls="radiobutton";text="不使用代理";left=14;top=370;right=120;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=6};
15 | radioProxyPac={cls="radiobutton";text="PAC代理";left=234;top=370;right=321;bottom=395;bgcolor=16777215;db=1;dl=1;font=LOGFONT(h=-13);z=5}
16 | )
17 | /*}}*/
18 |
19 | frmV2ray.show();
20 | frmV2ray.listview.insertColumn("类型",100)
21 | frmV2ray.listview.insertColumn("服务器",160)
22 | frmV2ray.listview.insertColumn("端口",70)
23 | frmV2ray.listview.insertColumn("加密",90)
24 | frmV2ray.listview.insertColumn("协议",50)
25 | frmV2ray.listview.insertColumn("备注",190)
26 | frmV2ray.listview.insertColumn("响应速度",80)
27 | frmV2ray.listview.insertColumn("状态",-1)
28 |
29 | import config;
30 | import v2ray.core;
31 | var currentOutboundIndex,currentOutboundAddress;
32 | var activeOutbound = function(outboundIndex,outboundAddress,enableRetry){
33 | if(!outboundIndex && !outboundAddress){
34 | outboundIndex,outboundAddress = currentOutboundIndex,currentOutboundAddress ;
35 | if(!outboundIndex && !outboundAddress) return;
36 | }
37 |
38 | var currentTesting = currentOutboundIndex == outboundIndex && currentOutboundAddress == outboundAddress;
39 | if( currentTesting || v2ray.core.restart(frmV2ray.edit,config.proxy.outbounds[outboundIndex]) ){
40 | currentOutboundIndex,currentOutboundAddress = outboundIndex,outboundAddress;
41 | frmV2ray.autoTesting = true;
42 |
43 | ..thread.invoke(
44 | function(frmV2ray,outboundIndex,outboundAddress,port,enableRetry,currentTesting){
45 |
46 | import wsock.tcp.socks5Client;
47 |
48 | var client;
49 | for(i=1;5;1){
50 | sleep(1000);
51 | client = wsock.tcp.socks5Client("127.0.0.1",port);
52 | if(client)break;
53 | }
54 | if(!client){
55 | frmV2ray.onStartV2rayFailed(outboundIndex);
56 | return;
57 | };
58 |
59 | client.setTimeouts(1000,1000);
60 | if(client.connect("www.google.com",80) ){
61 | var sendData =/***********
62 | GET / HTTP/1.1
63 | Host: www.google.com
64 | Connection: close
65 | User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64)
66 | Accept: */*;
67 | Accept-Language: zh-CN,zh;
68 | Accept-Charset:utf-8;
69 | ***********/
70 | client.write( sendData + '\r\n\r\n' )
71 | var rep = client.read(9);
72 | client.close();
73 |
74 | if(outboundAddress!=frmV2ray.listview.getItemText(outboundIndex,2)){
75 | return;
76 | }
77 |
78 | if( rep && ..string.startWith(rep,"HTTP/1.1 ") ){
79 |
80 | import inet.http;
81 | var http = inet.http(,"SOCKS=127.0.0.1:"+port);
82 | http.setTimeouts(1000,2000,2000);
83 | var html = http.get("https://www.google.com");
84 | http.close();
85 |
86 | if( html ){
87 | frmV2ray.onStartV2rayComplete(outboundIndex,currentTesting);
88 | return;
89 | }
90 | }
91 | }
92 |
93 | frmV2ray.onStartV2rayFailed(outboundIndex,enableRetry);
94 | },frmV2ray,outboundIndex,outboundAddress,v2ray.core.getPort(),enableRetry,currentTesting
95 | )
96 | }
97 | }
98 |
99 | frmV2ray.onStartV2rayComplete = function(outboundIndex,currentTesting){
100 | frmV2ray.listview.ensureVisible(outboundIndex);
101 |
102 | for b,v in table.eachIndex(config.proxy.outbounds){
103 | frmV2ray.listview.setItemText("",b,8);
104 | }
105 |
106 | frmV2ray.autoTesting = false;
107 | frmV2ray.listview.setItemText("活动服务器:正常",outboundIndex,8);
108 |
109 | if(!currentTesting) frmV2ray.edit.print("已切换到服务器:",frmV2ray.listview.getItemText(outboundIndex,2));
110 |
111 | if(frmV2ray.listview.getItemText(outboundIndex,7)=="不可用"){
112 | frmV2ray.listview.setItemText("...",outboundIndex,7);
113 | }
114 |
115 | frmV2ray.onTcpingReturn = function(){};
116 | frmV2ray.btnTcping.disabledText = null;
117 | frmV2ray.validOutbounds = {};
118 | }
119 |
120 | frmV2ray.onStartV2rayFailed = function(outboundIndex,enableRetry){
121 | frmV2ray.listview.ensureVisible(outboundIndex);
122 |
123 |
124 | if(enableRetry){
125 | if(#frmV2ray.validOutbounds){
126 | var next = table.shift(frmV2ray.validOutbounds);
127 | activeOutbound(next[1],next[2],#frmV2ray.validOutbounds);
128 | frmV2ray.listview.setItemText("异常,测试下一个...",outboundIndex,8);
129 | frmV2ray.edit.print("服务器异常:",frmV2ray.listview.getItemText(outboundIndex,2));
130 | frmV2ray.edit.print("正在尝试连接:",next[2]);
131 | }
132 | else {
133 | frmV2ray.btnTcping.oncommand();
134 | }
135 | }
136 | else {
137 | frmV2ray.listview.setItemText("活动服务器:异常",outboundIndex,8);
138 | frmV2ray.edit.print("已切换到服务器:",frmV2ray.listview.getItemText(outboundIndex,2));
139 | frmV2ray.autoTesting = false;
140 | }
141 |
142 | frmV2ray.btnTcping.disabledText = null;
143 | }
144 |
145 | var tcping = function(frmV2ray,outboundIndex,address){
146 | import wsock.tcp.client;
147 | var item = frmV2ray.listview.items[outboundIndex];
148 |
149 | var timeout = 0;
150 | for(i=1;8;1){
151 | var client = wsock.tcp.client();
152 | var tickBegin = time.tick();
153 | if(client.connectTimeout(item[2],tonumber(item[3]),3)){
154 | var ret = client.send(".");
155 | client.close();
156 |
157 | if( ret != 1){
158 | frmV2ray.listview.setItemText("不可用",outboundIndex,7);
159 | frmV2ray.onTcpingReturn(outboundIndex,address,false);
160 | return;
161 | }
162 | timeout = timeout + (time.tick() - tickBegin);
163 | }
164 | else {
165 | client.close();
166 | frmV2ray.listview.setItemText("不可用",outboundIndex,7);
167 | frmV2ray.onTcpingReturn(outboundIndex,address,false);
168 | return;
169 | }
170 | }
171 |
172 | frmV2ray.onTcpingReturn(outboundIndex,address,true);
173 | frmV2ray.listview.setItemText(math.round(timeout / 8 / 1000,2)+"秒",outboundIndex,7);
174 | };
175 |
176 | import style;
177 | frmV2ray.btnTcping.skin(style.primaryButton);
178 | frmV2ray.btnTcping.oncommand = function(id,event){
179 |
180 | var items = frmV2ray.listview.items;
181 | if(#items){
182 | frmV2ray.btnTcping.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
183 | if(!v2ray.core.getPath()){
184 | frmV2ray.btnTcping.disabledText = null;
185 | frmV2ray.msgErr("下载 v2ray.exe 失败")
186 | return;
187 | }
188 |
189 | var faieldCount = 0;
190 | frmV2ray.onTcpingReturn = function(outboundIndex,address,succeeded){
191 | if(address!=frmV2ray.listview.getItemText(outboundIndex,2)){
192 | return;
193 | }
194 |
195 | if(config.proxy.outbounds[outboundIndex].autoConnect === false ){
196 | faieldCount++;
197 | if(faieldCount==#items) frmV2ray.autoTesting = false;
198 | return;
199 | }
200 |
201 | if(succeeded){
202 | frmV2ray.validOutbounds = {}
203 | frmV2ray.onTcpingReturn = function(outboundIndex,address,succeeded){
204 | if(address!=frmV2ray.listview.getItemText(outboundIndex,2)){
205 | return;
206 | }
207 |
208 | if(config.proxy.outbounds[outboundIndex].autoConnect === false ){
209 | faieldCount++;
210 | if(faieldCount==#items) frmV2ray.autoTesting = false;
211 | return;
212 | }
213 |
214 | if(succeeded) table.push(frmV2ray.validOutbounds,{outboundIndex;address});
215 | else{
216 | faieldCount++;
217 | if(faieldCount==#items) frmV2ray.autoTesting = false;
218 | }
219 | }
220 | activeOutbound(outboundIndex,address,#items>1);
221 | }
222 | else{
223 | faieldCount++;
224 | if(faieldCount==#items) frmV2ray.autoTesting = false;
225 | }
226 | }
227 |
228 | for b,v in table.eachIndex(config.proxy.outbounds){
229 | frmV2ray.listview.setItemText("...",b,7);
230 | frmV2ray.listview.setItemText("",b,8);
231 | }
232 |
233 | var handles = {}
234 | thread.createSuspended(true);
235 | for(i=1;#items;1){
236 | var h = thread.create(tcping,frmV2ray,i,frmV2ray.listview.getItemText(i,2));
237 | table.push(handles,h);
238 | }
239 | thread.createSuspended(false);
240 |
241 | var dnsapi = ..raw.loadDll("dnsapi.dll");
242 | dnsapi.DnsFlushResolverCacheB();
243 |
244 | for(i=1;#handles;1){
245 | var h = handles[i];
246 | thread.resume(h);
247 | raw.closehandle(h);
248 | }
249 |
250 | ..thread.waitOne(handles);
251 | frmV2ray.btnTcping.disabledText = null;
252 | }
253 | else {
254 | if(id) frmV2ray.msgWarn("请先添加服务器")
255 | }
256 | }
257 |
258 | frmV2ray.onDestroy = function(){
259 | v2ray.core.stop();
260 | }
261 |
262 | frmV2ray.listview.onnotify = function(id,code,ptr){
263 | select(code) {
264 | case 0xFFFFFFF4/*_NM_CUSTOMDRAW*/ {
265 | var lvcd = frmV2ray.listview.getNotifyCustomDraw(code,ptr);
266 | if( lvcd.nmcd.dwDrawStage == 0x10001/*_CDDS_ITEMPREPAINT*/)
267 | return 0x20/*_CDRF_NOTIFYSUBITEMDRAW*/
268 | elseif( lvcd.nmcd.dwDrawStage == 1/*_CDDS_PREPAINT*/ ){
269 | return 0x20/*_CDRF_NOTIFYITEMDRAW*/;
270 | }
271 | elseif( lvcd.nmcd.dwDrawStage == ( 0x10001/*_CDDS_ITEMPREPAINT*/ | 0x20000/*_CDDS_SUBITEM*/) ){
272 | //注意这里 iSubItem 的索引自0开始( 其他函数通常自1开始 )
273 | lvcd.clrText = lvcd.nmcd.dwItemSpec % 2 ? 0x373737 : 0;
274 | lvcd.clrTextBk = lvcd.nmcd.dwItemSpec % 2 ? 0xFFFFFF : 0xF5F5F5;
275 | lvcd.update()
276 |
277 | return 0/*_CDRF_DODEFAULT*/
278 | }
279 | }
280 | case 0xFFFFFFFD/*_NM_DBLCLK*/ {
281 | var nm = frmV2ray.listview.getNotifyMessage(code,ptr);
282 | if( nm ){
283 | frmV2ray.onTcpingReturn = function(i){}
284 | frmV2ray.btnTcping.disabledText = null;
285 |
286 | for b,v in table.eachIndex(config.proxy.outbounds){
287 | frmV2ray.listview.setItemText("",b,8);
288 | }
289 | activeOutbound(nm.iItem,frmV2ray.listview.getItemText(nm.iItem,2),false);
290 | }
291 | }
292 | case 0xFFFFFFFB/*_NM_RCLICK*/ {
293 | var x,y = win.getCursorPos();
294 | var nm = frmV2ray.listview.getNotifyMessage(code,ptr);
295 | if(!nm) return;
296 |
297 | var currentIdx = nm.iItem;
298 | var popmenu = win.ui.popmenu(frmV2ray);
299 | popmenu.add('设为活动服务器( 鼠标双击 )',function(id){
300 | if(currentIdx){
301 | frmV2ray.onTcpingReturn = function(i){}
302 | frmV2ray.btnTcping.disabledText = null;
303 |
304 | for b,v in table.eachIndex(config.proxy.outbounds){
305 | frmV2ray.listview.setItemText("",b,8);
306 | }
307 | activeOutbound(currentIdx,frmV2ray.listview.getItemText(currentIdx,2),false)
308 | }
309 | });
310 |
311 | popmenu.add('允许被自动选择为活动服务器',function(id){
312 | if(currentIdx){
313 | if(config.proxy.outbounds[currentIdx].autoConnect === false){
314 | config.proxy.outbounds[currentIdx].autoConnect = null;
315 | }
316 | else {
317 | config.proxy.outbounds[currentIdx].autoConnect = false;
318 | }
319 |
320 | }
321 | });
322 | popmenu.check(2,config.proxy.outbounds[currentIdx].autoConnect!==false);
323 |
324 | popmenu.add('复制服务器链接',function(id){
325 | if(currentIdx){
326 | import v2ray.config;
327 | import win.clip;
328 |
329 | var str = v2ray.config.exportToString({config.proxy.outbounds[currentIdx]});
330 | if(str){
331 | win.clip.write(str);
332 | frmV2ray.edit.print("已复制链接:",str);
333 | }
334 | }
335 | });
336 | popmenu.add();
337 | popmenu.add('删除服务器',function(id){
338 | if(currentIdx){
339 | frmV2ray.listview.delItem(currentIdx);
340 | ..table.remove(config.proxy.outbounds,currentIdx);
341 | publish("config.proxy.outbounds.config.changed");
342 | }
343 | });
344 | popmenu.popup(x,y,true);
345 | }
346 | }
347 | }
348 |
349 | subscribe("config.proxy.outbounds.changed",function(){
350 | config.proxy.outbounds.fields = {"protocol";"address";"port";"security";"network";"ps";}
351 | frmV2ray.listview.setTable(config.proxy.outbounds);
352 |
353 | frmV2ray.btnTcping.oncommand();
354 | } )
355 |
356 | import process;
357 | process.kill("v2ray.exe");
358 | if(#config.proxy.outbounds){
359 | frmV2ray.setTimeout(
360 | function(){
361 | publish("config.proxy.outbounds.changed");
362 | },1000
363 | );
364 | }
365 |
366 | subscribe("config.proxy.mode.changed",function(...){
367 | frmV2ray.radioProxyPac.checked = false;
368 | frmV2ray.radioProxy.checked = false;
369 | frmV2ray.radioProxyDirect.checked = false;
370 |
371 | if(config.proxy.mode = "pac"){
372 | frmV2ray.radioProxyPac.checked = true;
373 | }
374 | elseif(config.proxy.mode = "proxy"){
375 | frmV2ray.radioProxy.checked = true;
376 | }
377 | else{
378 | frmV2ray.radioProxyDirect.checked = true;
379 | }
380 | } )
381 | publish("config.proxy.mode.changed");
382 |
383 | var updatProxySetting = function(){
384 | if(frmV2ray.radioProxyPac.checked){
385 | config.proxy.mode = "pac";
386 | inet.conn.setProxyAutoConfig(,v2ray.core.getPacUrl() )
387 | }
388 | elseif(frmV2ray.radioProxy.checked){
389 | config.proxy.mode = "proxy";
390 | inet.conn.setProxy(,"SOCKS=127.0.0.1:"+v2ray.core.getPort());
391 | }
392 | else {
393 | config.proxy.mode = "direct";
394 | inet.conn.setProxy();
395 | }
396 |
397 | config.proxy.save();
398 | }
399 | frmV2ray.radioProxyPac.oncommand = updatProxySetting;
400 | frmV2ray.radioProxy.oncommand = updatProxySetting;
401 | frmV2ray.radioProxyDirect.oncommand = updatProxySetting;
402 |
403 | import win.dlg.message
404 | win.dlg.message.install()
405 | frmV2ray.btnEditPac.skin(style.plainButton)
406 | frmV2ray.btnEditPac.oncommand = function(id,event){
407 | if(frmPac && win.isWindow(frmPac.hwnd)){
408 | if( isIconic(frmPac.hwnd) ) win.show(frmPac.hwnd,9/*_SW_RESTORE*/ );
409 | if( !isVisible(frmPac.hwnd) ) win.show(frmPac.hwnd,0x1/*_SW_NORMAL*/ );
410 | win.setForeground(frmPac.hwnd)
411 | return;
412 | }
413 |
414 | frmPac = frmV2ray.loadForm("\forms\main\pac.aardio");
415 | frmPac.show();
416 | }
417 |
418 | frmV2ray.btnImportServerFromClipBd.skin(style.plainButton)
419 | frmV2ray.btnImportServerFromClipBd.oncommand = function(id,event){
420 | var outbounds = v2ray.config.importFromClip();
421 | if(#outbounds){
422 | ..table.append(config.proxy.outbounds,outbounds);
423 | publish("config.proxy.outbounds.changed");
424 | publish("config.proxy.outbounds.config.changed");
425 | frmV2ray.msgOk("已成功导入" + #outbounds + "个服务器");
426 | return;
427 | }
428 |
429 | frmV2ray.msgFrown("未导入服务器, 请先复制 vmess://、ss:// 链接、或订阅源!")
430 | }
431 |
432 | var testTimerId;
433 | frmV2ray.chkAutoTest.oncommand = function(id,event){
434 | if(testTimerId){
435 | frmV2ray.clearInterval(testTimerId);
436 | }
437 |
438 | config.proxy.test = frmV2ray.chkAutoTest.checked;
439 | if(!config.proxy.test) return;
440 |
441 | testTimerId = frmV2ray.setInterval(
442 | 15000,function(){
443 | if( frmV2ray.autoTesting ) return;
444 | frmV2ray.autoTesting = true;
445 |
446 | activeOutbound(,,true);
447 | }
448 | )
449 | }
450 |
451 | if(config.proxy.test){
452 | frmV2ray.chkAutoTest.checked = true;
453 | frmV2ray.chkAutoTest.oncommand();
454 | }
455 |
456 | frmV2ray.chkAutoTest.skin(style.checkBox);
457 |
458 | frmV2ray.enableDpiScaling();
459 | return win.loopMessage();
--------------------------------------------------------------------------------
/lib/config.aardio:
--------------------------------------------------------------------------------
1 | //config 配置文件
2 | import v2ray.config;
3 | import fsys.config;
4 | config = fsys.config( io.appData("/win2ray-v2/") );
5 |
6 | namespace config {
7 | __appName = "win2ray";
8 | __loadDefaultOutbounds = function(){
9 | var serverData = ..string.load("/v2ray-core/win2ray-default-servers.json")
10 | : $"/v2ray-core/win2ray-default-servers.json"
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 | if(!#outbound.security) outbound.security = "auto";
19 |
20 | var ob = {
21 | mux={
22 | concurrency=8;
23 | enabled=true
24 | };
25 | protocol="vmess";
26 | settings={
27 | vnext={
28 | {
29 | address=outbound.address;
30 | level=outbound.level : null;
31 | port=tonumber(outbound.port);
32 | users={
33 | {
34 | alterId=outbound.alterId : 0;
35 | email=outbound.email : "t@t.tt";
36 | id=outbound.id;
37 | security=outbound.security;
38 | }
39 | }
40 | }
41 | };
42 | };
43 | streamSettings={
44 | network=outbound.network : "tcp";
45 | security=#outbound.tls ? outbound.tls : null;
46 | tlsSettings = #outbound.tls ? {
47 | allowInsecure = outbound.tlsAllowInsecure;
48 | serverName = outbound.tlsServerName;
49 | } : null
50 | };
51 | tag="proxy"
52 | };
53 |
54 | if( outbound.network == "ws" ){
55 | ob.streamSettings.wsSettings = {
56 | path = outbound.path;
57 | headers = outbound.headers;
58 | connectionReuse = true;
59 | }
60 |
61 | if( outbound.host ) {
62 | if(!ob.streamSettings.wsSettings.headers){
63 | ob.streamSettings.wsSettings.headers = {}
64 | }
65 | ob.streamSettings.wsSettings.headers.Host = outbound.host;
66 | }
67 | }
68 | elseif( outbound.network == "http" ){
69 | ob.streamSettings.httpSettings = {
70 | connectionReuse = true;
71 | path = outbound.path;
72 | host = outbound.host;
73 | }
74 | }
75 | elseif( outbound.network == "tcp" ){
76 | if( outbound.type == "http" ){
77 | ob.streamSettings.tcpSettings = {
78 | connectionReuse = true;
79 | header = {
80 | request={
81 | headers={
82 | Connection={
83 | "keep-alive"
84 | };
85 | Host=outbound.host;
86 | Pragma="no-cache";
87 | ["Accept-Encoding"]={
88 | "gzip, deflate"
89 | };
90 | ["User-Agent"]={
91 | "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.75 Safari/537.36";
92 | "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"
93 | }
94 | };
95 | method="GET";
96 | path = outbound.path;
97 | version="1.1"
98 | };
99 | type="http";
100 | }
101 | }
102 | }
103 | }
104 |
105 | current.outbounds[1] = ob;
106 | }
107 | elseif(outbound.protocol=="shadowsocks"){
108 | current.outbounds[1] = {
109 | mux={
110 | concurrency=-1;
111 | enabled=false
112 | };
113 | protocol="shadowsocks";
114 | settings={
115 | servers={
116 | {
117 | address=outbound.address;
118 | level=outbound.level : 0;
119 | method=outbound.security;
120 | ota=false;
121 | password=outbound.id;
122 | port=outbound.port;
123 | }
124 | };
125 | };
126 | streamSettings={
127 | network = outbound.network : "tcp";
128 | };
129 | tag="proxy"
130 | };
131 | }
132 |
133 | ..thread.set("v2ray.core.config",web.json.stringify(current))
134 | }
135 |
136 | getConfigJson = function(){
137 | return ..thread.get("v2ray.core.config");
138 | }
139 |
140 | exportToString = function(outbounds){
141 | import web.json;
142 | import crypt;
143 |
144 | var outString = {};
145 | for i,outbound in ..table.eachIndex(outbounds){
146 | if(outbound.protocol == "vmess"){
147 | var json = ..web.json.stringify({
148 | v = 2;
149 | add = outbound.address;
150 | aid = outbound.alterId;
151 | id = outbound.id;
152 | port = outbound.port;
153 | net = outbound.network;
154 | type = outbound.type;
155 | path = outbound.path;
156 | host = outbound.host;
157 | tls = outbound.tls;
158 | ps = outbound.ps;
159 | })
160 |
161 | var vmess = "vmess://" + ..crypt.encodeBin(json);
162 | ..table.push(outString,vmess);
163 | }
164 | elseif(outbound.protocol == "shadowsocks"){
165 | var ss = "ss://" + ..crypt.encodeBin( outbound.security + ":" + outbound.id + "@" + outbound.address + ":" + outbound.port) + "#" + outbound.address + ":" + outbound.port;
166 | ..table.push(outString,ss);
167 | }
168 | }
169 |
170 | return ..string.join(outString,'\r\n');
171 | }
172 |
173 | import crypt;
174 | import inet.http;
175 | importFromString = function(str){
176 | import config;
177 | import web.json;
178 | import crypt;
179 |
180 | if(!str){ return; }
181 |
182 | str = ..string.trim(str);
183 |
184 | if( ..string.match(str,"%\[\]") ){
185 | var cfg = web.json.tryParse(str);
186 | if(type(cfg)==type.table && #cfg){
187 | return cfg;
188 | }
189 | }
190 |
191 | var subscribeUrl;
192 | if( ..string.startWith(str,"http://") || ..string.startWith(str,"https://") ){
193 |
194 | import win.dlg.message;
195 | var msgDlg = win.dlg.message(..mainForm);
196 | var form = msgDlg.create('正在获取订阅源 ... ',,true)
197 | form.progress.startProgress(50);
198 |
199 | subscribeUrl = str;
200 | str = ..win.invoke(
201 | function(subscribeUrl){
202 | import inet.http;
203 | return inet.http().get(subscribeUrl);
204 | },subscribeUrl
205 | )
206 |
207 | form.close();
208 | if(!str){
209 | return;
210 | }
211 | }
212 |
213 | if(..string.match(str,"^[\w=+]+$")){
214 | str = ..crypt.decodeBin(str);
215 | if(!str) return;
216 | }
217 |
218 | var outbounds = ..table.array();
219 | for(line in ..string.lines(str) ){
220 | if(line[1]=='/'# && line[2]=='/'#){
221 | continue;
222 | }
223 |
224 | var vmess = ..string.match(line,`vmess\:\/\/([\w=+]+)`);
225 | if( vmess ) {
226 | var json = ..crypt.decodeBin(vmess);
227 | var outbound = ..web.json.tryParse(json);
228 | if(outbound){
229 | ..table.clear(outbound@._defined);
230 | outbound.protocol = "vmess";
231 | outbound.address = outbound.add;
232 | outbound.alterId = outbound.aid;
233 | outbound.security = "auto";
234 | outbound.network = outbound.net : "tcp";
235 | outbound.net = null;
236 | outbound.add = null;
237 | outbound.aid = null;
238 | outbound.v = null;
239 | outbound.subscribeUrl = subscribeUrl;
240 | ..table.push(outbounds,outbound);
241 | }
242 |
243 | continue;
244 | }
245 |
246 | var ss = ..string.match(line,`ss\:\/\/([\w=+]+)`);
247 | if( ss ) {
248 | var ss = ..crypt.decodeBin(ss);
249 | var method,password,address,port = ..string.match(ss,"^(.+)\:(.+)\@(.+)\:(\d+)")
250 |
251 | if(address && password && port){
252 | var outbound = {
253 | address = address;
254 | port = tonumber(port);
255 | security = method;
256 | id = password;
257 | network = "tcp";
258 | protocol = "shadowsocks"
259 | };
260 |
261 | outbound.subscribeUrl = subscribeUrl;
262 | ..table.push(outbounds,outbound);
263 | }
264 |
265 | continue;
266 | }
267 |
268 | var address,port,id,network,path,tls = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+([\w-]+)\s+(\a+)\s+(\S+)\s+(\a+)")
269 | if(!address) address,port,id,network,path = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+(\S+)\s+(\a+)\s+(\S+)")
270 | if(!address) address,port,id,network = ..string.match(line,"(<\w+\.>+\w+)\s+(\d+)\s+(\S+)\s+(\a+)")
271 |
272 | if(address && port && id){
273 | var outbound = {
274 | address = address;
275 | port = tonumber(port);
276 | id = id;
277 | network = network;
278 | path = path;
279 | tls = tls;
280 | security= "auto";
281 | protocol = "vmess"
282 | }
283 |
284 | if(path){
285 | var t,h,p = ..string.match(path,"(\w*)\:\/\/([^/]+)(.+)");
286 | if(t&&h){
287 | if(t!=network) outbound.type = t;
288 | outbound.host = h;
289 | outbound.path = p;
290 | }
291 | }
292 |
293 | if(outbound.network=="shadowsocks"){
294 | outbound.network = "tcp";
295 | outbound.protocol = "shadowsocks";
296 | outbound.security = outbound.path;
297 | outbound.path = null;
298 | }
299 |
300 | outbound.subscribeUrl = subscribeUrl;
301 | ..table.push(outbounds,outbound)
302 | }
303 | }
304 |
305 | if(#outbounds){
306 |
307 | }
308 | return outbounds;
309 | }
310 |
311 | importFromClip = function(){
312 | import win.clip;
313 | var str = ..win.clip.read();
314 | if(!str){ return; }
315 |
316 | return importFromString(str);
317 | }
--------------------------------------------------------------------------------
/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-v2/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-v2/download/")
42 | ,..io.appData("/win2ray-v2/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-v2/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 = 50;
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.setProxy(,"SOCKS=127.0.0.1:" + inboundPort.get());
113 | ..inet.conn.setProxyAutoConfig(,getPacUrl());
114 | }
115 | elseif(..config.proxy.mode === "proxy"){
116 | ..inet.conn.setProxyAutoConfig(,getPacUrl())
117 |
118 |
119 | ..inet.conn.setProxy(,"SOCKS=127.0.0.1:" + inboundPort.get());
120 | }
121 | else {
122 | ..inet.conn.setProxy();
123 | }
124 | return true;
125 | }
126 |
127 | stop = function(){
128 | if(prcsv2ray){
129 | prcsv2ray.terminate();
130 | prcsv2ray = null;
131 | }
132 |
133 | if(serverMain){
134 | serverMain.stop();
135 | serverMain = null;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/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 | mainForm.popmenu.add();
126 |
127 | mainForm.popmenu.add('退出',function(id){
128 | mainForm.onClose = null;
129 | mainForm.close()
130 | });
131 |
132 | var pt = ::POINT();
133 | ::User32.GetCursorPos(pt);
134 | mainForm.popmenu.popup(pt.x,pt.y,true)
135 | }
136 | elseif( lParam = 0x203/*_WM_LBUTTONDBLCLK*/) {
137 | mainForm.show();
138 | win.setForeground(mainForm.hwnd);
139 | }
140 | }
141 | }
142 |
143 | mainForm.enableDpiScaling();
144 |
145 | mainForm.show();
146 | return win.loopMessage();
147 |
--------------------------------------------------------------------------------
/screenshots/config.json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/screenshots/config.json.png
--------------------------------------------------------------------------------
/screenshots/pac.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/screenshots/pac.jpg
--------------------------------------------------------------------------------
/screenshots/win2ray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/screenshots/win2ray.png
--------------------------------------------------------------------------------
/v2ray-core/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015-2019 V2Ray
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.
--------------------------------------------------------------------------------
/v2ray-core/v2ctl.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/v2ray-core/v2ctl.exe
--------------------------------------------------------------------------------
/v2ray-core/v2ray.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/v2ray-core/v2ray.exe
--------------------------------------------------------------------------------
/v2ray-core/win2ray-default-servers.json:
--------------------------------------------------------------------------------
1 | // 号开头为注释行。
2 | // 可以文本格式指定服务器数组,每行一个服务器配置,
3 | // vmess 服务器每行字段依次为 address port id network path tls
4 | // ss 服务器每行字段依次为 address port password shadowsocks method
5 | // 也可以每行一个vmess://或ss://链接
6 | // 本文件可以直接输入json格式的服务器数组( 服务器可以使用subscribeUrl字段指定订阅源地址,可以指定"autoConnect":false字段禁止自动连接 )
7 | [
8 | {
9 | "address": "c26s3.jamjams.net",
10 | "id": "0a021043-fb2e-4ecd-8d17-e62922b3aca7",
11 | "network": "tcp",
12 | "port": 50201,
13 | "protocol": "vmess",
14 | "ps": "CN2 GIA 直连",
15 | "security": "auto"
16 | },
17 | {
18 | "address": "c26s4.jamjams.net",
19 | "id": "0a021043-fb2e-4ecd-8d17-e62922b3aca7",
20 | "network": "tcp",
21 | "port": 50201,
22 | "protocol": "vmess",
23 | "ps": "CN2 GT 直连",
24 | "security": "auto"
25 | },
26 | {
27 | "address": "c26s5.jamjams.net",
28 | "id": "0a021043-fb2e-4ecd-8d17-e62922b3aca7",
29 | "network": "tcp",
30 | "port": 50201,
31 | "protocol": "vmess",
32 | "ps": "CN2 GT 直连",
33 | "security": "auto"
34 | },
35 | {
36 | "address": "c26s801.jamjams.net",
37 | "id": "0a021043-fb2e-4ecd-8d17-e62922b3aca7",
38 | "network": "tcp",
39 | "port": 50201,
40 | "protocol": "vmess",
41 | "ps": "ChinaNet 直连丨0.1x",
42 | "security": "auto"
43 | },
44 | {
45 | "address": "c26s1.jamjams.net",
46 | "id": "yjxz4ZBs8B",
47 | "network": "tcp",
48 | "port": 50201,
49 | "protocol": "shadowsocks",
50 | "ps": "CN2 GT 直连",
51 | "security": "aes-256-gcm"
52 | },
53 | {
54 | "address": "c26s2.jamjams.net",
55 | "id": "yjxz4ZBs8B",
56 | "network": "tcp",
57 | "port": 50201,
58 | "protocol": "shadowsocks",
59 | "ps": "CN2 GT 直连",
60 | "security": "aes-256-gcm"
61 | }
62 | ]
--------------------------------------------------------------------------------
/win2ray.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iuuniang/win2ray/fb32f0e8f71c7d353cbb8c721b6a022f4ef350f3/win2ray.exe
--------------------------------------------------------------------------------