mirror of
https://github.com/torappinfo/uweb.git
synced 2024-08-14 23:54:59 +00:00
420 lines
12 KiB
JavaScript
420 lines
12 KiB
JavaScript
|
const {
|
||
|
app, BrowserWindow, Menu, shell, clipboard,
|
||
|
session, protocol, net} = require('electron')
|
||
|
let win;
|
||
|
|
||
|
if(!app.requestSingleInstanceLock())
|
||
|
app.quit()
|
||
|
else {
|
||
|
app.on('ready', createWindow);
|
||
|
app.on('second-instance', (event, args, cwd) => {
|
||
|
// 当已经有运行的实例时,我们激活窗口而不是创建新的窗口
|
||
|
if (win) {
|
||
|
if (win.isMinimized()) {
|
||
|
win.restore()
|
||
|
}
|
||
|
win.show()
|
||
|
win.focus()
|
||
|
cmdlineProcess(args,cwd,1);
|
||
|
}else
|
||
|
createWindow();
|
||
|
})
|
||
|
}
|
||
|
topMenu();
|
||
|
|
||
|
const fs = require('fs');
|
||
|
const readline = require('readline');
|
||
|
const path = require('path')
|
||
|
const process = require('process')
|
||
|
var gredirects = [];
|
||
|
var gredirect;
|
||
|
var redirects;
|
||
|
var bRedirect = true;
|
||
|
var bJS = true;
|
||
|
var bHistory = false;
|
||
|
var proxies = {};
|
||
|
var proxy;
|
||
|
var useragents = {};
|
||
|
var defaultUA =
|
||
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" +
|
||
|
process.versions.chrome +" Safari/537.36";
|
||
|
app.userAgentFallback = defaultUA;
|
||
|
var historyFile = path.join(__dirname,'history.rec');
|
||
|
|
||
|
fs.readFile(path.join(__dirname,'redirect.json'), 'utf8', (err, jsonString) => {
|
||
|
if (err) return;
|
||
|
try {
|
||
|
redirects = JSON.parse(jsonString);
|
||
|
} catch (e){}
|
||
|
});
|
||
|
|
||
|
async function createWindow () {
|
||
|
let json = await fs.promises.readFile(path.join(__dirname,'uas.json'), 'utf8');
|
||
|
try {
|
||
|
useragents = JSON.parse(json);
|
||
|
} catch (e){}
|
||
|
|
||
|
await (async ()=>{
|
||
|
try{
|
||
|
const readInterface = readline.createInterface ({
|
||
|
input: fs.createReadStream (path.join(__dirname,'config'), 'utf8'),
|
||
|
});
|
||
|
|
||
|
for await (const line of readInterface) {
|
||
|
addrCommand(line);
|
||
|
}
|
||
|
}catch(e){return;}
|
||
|
})();
|
||
|
|
||
|
win = new BrowserWindow(
|
||
|
{width: 800, height: 600,autoHideMenuBar: true,
|
||
|
webPreferences: {
|
||
|
nodeIntegration: true,
|
||
|
contextIsolation: false,
|
||
|
webviewTag: true,
|
||
|
}});
|
||
|
win.setMenuBarVisibility(false);
|
||
|
win.on('closed', function () {
|
||
|
win = null
|
||
|
})
|
||
|
|
||
|
win.loadFile('index.html');
|
||
|
fs.readFile(path.join(__dirname,'gredirect.json'), 'utf8', (err, jsonString) => {
|
||
|
if (err) return;
|
||
|
try {
|
||
|
gredirects = JSON.parse(jsonString);
|
||
|
} catch (e){}
|
||
|
});
|
||
|
|
||
|
fs.readFile(path.join(__dirname,'proxy.json'), 'utf8', (err, jsonString) => {
|
||
|
if (err) return;
|
||
|
try {
|
||
|
proxies = JSON.parse(jsonString, (key,val)=>{
|
||
|
if(!proxy && key==="proxyRules"){
|
||
|
proxy = {proxyRules:val};
|
||
|
}
|
||
|
return val;
|
||
|
});
|
||
|
} catch (e){}
|
||
|
});
|
||
|
|
||
|
cmdlineProcess(process.argv, process.cwd(), 0);
|
||
|
//app.commandLine.appendSwitch ('trace-warnings');
|
||
|
|
||
|
win.webContents.on('page-title-updated',(event,cmd)=>{
|
||
|
addrCommand(cmd);
|
||
|
});
|
||
|
|
||
|
win.webContents.on('console-message',cbConsoleMsg);
|
||
|
//protocol.handle("https",cbScheme_https);
|
||
|
}
|
||
|
|
||
|
app.on('window-all-closed', function () {
|
||
|
app.quit()
|
||
|
})
|
||
|
|
||
|
app.on('activate', function () {
|
||
|
if (win === null) {
|
||
|
createWindow()
|
||
|
}
|
||
|
})
|
||
|
|
||
|
app.on('will-quit', () => {
|
||
|
})
|
||
|
|
||
|
app.on ('web-contents-created', (event, contents) => {
|
||
|
if (contents.getType () === 'webview') {
|
||
|
contents.setWindowOpenHandler(cbWindowOpenHandler);
|
||
|
contents.on('context-menu',onContextMenu);
|
||
|
contents.on('page-title-updated',cbTitleUpdate);
|
||
|
//contents.on('console-message',cbConsoleMsg);
|
||
|
//contents.on('focus', ()=>{cbFocus(contents)});
|
||
|
//contents.on('blur',()=>{cbBlur()});
|
||
|
contents.session.webRequest.onBeforeRequest(interceptRequest);
|
||
|
contents.on('did-finish-load',()=>{cbFinishLoad(contents)});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function addrCommand(cmd){
|
||
|
if(cmd.length<3) return;
|
||
|
let c0 = cmd.charCodeAt(0);
|
||
|
switch(c0){
|
||
|
case 58: //':'
|
||
|
args = cmd.substring(1).split(/\s+/);
|
||
|
switch(args[0]){
|
||
|
case "cert":
|
||
|
if(args.length==1)
|
||
|
session.defaultSession.setCertificateVerifyProc((request, callback) => {
|
||
|
callback(0);
|
||
|
});
|
||
|
else
|
||
|
session.defaultSession.setCertificateVerifyProc(null);
|
||
|
return;
|
||
|
case "clear":
|
||
|
if(args.length==1){
|
||
|
return;
|
||
|
}
|
||
|
switch(args[1]){
|
||
|
case "cache":
|
||
|
session.defaultSession.clearCache();
|
||
|
return;
|
||
|
case "dns":
|
||
|
session.defaultSession.clearHostResolverCache();
|
||
|
return;
|
||
|
case "storage":
|
||
|
session.defaultSession.clearStorageData();
|
||
|
return;
|
||
|
}
|
||
|
return;
|
||
|
case "ext":
|
||
|
session.defaultSession.loadExtension(args[1]);
|
||
|
return;
|
||
|
case "nh":
|
||
|
bHistory = false; return;
|
||
|
case "uh":
|
||
|
bHistory = true; return;
|
||
|
case "nj":
|
||
|
bJS = false; return;
|
||
|
case "uj":
|
||
|
bJS = true; return;
|
||
|
case "np":
|
||
|
session.defaultSession.setProxy ({mode:"direct"});
|
||
|
return;
|
||
|
case "up":
|
||
|
if(args.length>1)
|
||
|
proxy = proxies[args[1]]; //retrieve proxy
|
||
|
if(proxy)
|
||
|
session.defaultSession.setProxy(proxy);
|
||
|
bRedirect = false;
|
||
|
return;
|
||
|
case "nr":
|
||
|
bRedirect = false; return;
|
||
|
case "ur":
|
||
|
bRedirect = true; return;
|
||
|
case "ua":
|
||
|
if(args.length==2)
|
||
|
session.defaultSession.setUserAgent(useragents[args[1]]);
|
||
|
else
|
||
|
session.defaultSession.setUserAgent(defaultUA);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function cbConsoleMsg(e, level, msg, line, sourceid){
|
||
|
console.log(line);
|
||
|
console.log(sourceid);
|
||
|
console.log(msg);
|
||
|
}
|
||
|
|
||
|
function cbFinishLoad(webContents){
|
||
|
if(!bHistory) return;
|
||
|
let histItem = webContents.getTitle()+" "+webContents.getURL()+"\n";
|
||
|
fs.appendFile(historyFile, histItem, (err) => {});
|
||
|
}
|
||
|
|
||
|
function cbFocus(webContents){
|
||
|
let js = "if(focusMesg){let m=focusMesg;focusMesg=null;m}";
|
||
|
win.webContents.executeJavaScript(js,false).then((r)=>{
|
||
|
//focusMesg as js code
|
||
|
console.log(r);
|
||
|
if(r) webContents.executeJavaScript(r,false);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function interceptRequest(details, callback){
|
||
|
if(!bJS && details.url.endsWith(".js")){
|
||
|
callback({ cancel: true });
|
||
|
return;
|
||
|
}
|
||
|
do {
|
||
|
if(gredirect){
|
||
|
if(!details.url.startsWith("http")) break;
|
||
|
if(!details.url.startsWith(gredirect)){
|
||
|
if(details.resourceType === 'mainFrame'){
|
||
|
let wc = details.webContents;
|
||
|
let url = details.url;
|
||
|
if(wc){
|
||
|
let nUrl = gredirect+url;
|
||
|
fetch(nUrl).then(res=>{
|
||
|
if(res.ok) return res.arrayBuffer();
|
||
|
throw new Error(`Err: ${res.status} - ${res.statusText}`);
|
||
|
}).then(aBuf=>{
|
||
|
const u8 = new Uint8Array(aBuf);
|
||
|
const b64 = Buffer.from (u8).toString('base64');
|
||
|
const dataUrl = `data:text/html;base64,${b64}`;
|
||
|
wc.loadURL(dataUrl,{baseURLForDataURL:url});
|
||
|
}).catch(e=>{
|
||
|
console.log(nUrl+" err:",e);
|
||
|
});
|
||
|
callback({ cancel: true });
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
let newUrl = gredirect + details.url;
|
||
|
callback({ cancel: false, redirectURL: newUrl });
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(!bRedirect ||(details.resourceType !== 'mainFrame' &&
|
||
|
details.resourceType !== 'subFrame')) break;
|
||
|
let oURL = new URL(details.url);
|
||
|
let domain = oURL.hostname;
|
||
|
let newUrl;
|
||
|
try{
|
||
|
let newDomain = redirects[domain];
|
||
|
if(!newDomain) break;
|
||
|
newUrl = "https://"+newDomain+oURL.pathname+oURL.search+oURL.hash;
|
||
|
}catch(e){break;}
|
||
|
callback({ cancel: false, redirectURL: newUrl });
|
||
|
return;
|
||
|
}while(false);
|
||
|
callback({ cancel: false });
|
||
|
}
|
||
|
|
||
|
function cbWindowOpenHandler(details){
|
||
|
let url = details.url;
|
||
|
let js = "newTab();tabs.children[tabs.children.length-1].src='"+
|
||
|
url+"';";
|
||
|
switch(details.disposition){
|
||
|
case "foreground-tab":
|
||
|
case "new-window":
|
||
|
js = js + "switchTab(tabs.children.length-1)";
|
||
|
}
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
return { action: "deny" };
|
||
|
}
|
||
|
function cbTitleUpdate(event,title){
|
||
|
win.setTitle(title);
|
||
|
}
|
||
|
function menuArray(labelprefix, linkUrl){
|
||
|
const menuTemplate = [
|
||
|
{
|
||
|
label: labelprefix+'Open Link',
|
||
|
click: () => {
|
||
|
shell.openExternal(linkUrl);
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
label: labelprefix+'Copy Link',
|
||
|
click: () => {
|
||
|
clipboard.writeText(linkUrl);
|
||
|
}
|
||
|
},
|
||
|
{
|
||
|
label: labelprefix+'Download',
|
||
|
click: () => {
|
||
|
win.contentView.children[i].webContents.downloadURL(linkUrl);
|
||
|
}
|
||
|
},
|
||
|
];
|
||
|
return menuTemplate;
|
||
|
}
|
||
|
|
||
|
function onContextMenu(event, params){
|
||
|
let url = params.linkURL;
|
||
|
let mTemplate = [];
|
||
|
if (url) {
|
||
|
mTemplate.push({label:url,enabled:false});
|
||
|
mTemplate.push.apply(mTemplate,menuArray("",url));
|
||
|
if((url=params.srcURL))
|
||
|
mTemplate.push.apply(mTemplate,menuArray("src: ",url));
|
||
|
}else if((url=params.srcURL)){
|
||
|
mTemplate.push({label:url,enabled:false});
|
||
|
mTemplate.push.apply(mTemplate,menuArray("src: ",url));
|
||
|
}else
|
||
|
return;
|
||
|
|
||
|
const contextMenu = Menu.buildFromTemplate(mTemplate);
|
||
|
contextMenu.popup();
|
||
|
}
|
||
|
|
||
|
function topMenu(){
|
||
|
const menuTemplate = [
|
||
|
{
|
||
|
label: '',
|
||
|
submenu: [
|
||
|
{ label: '', accelerator: 'Ctrl+G', click: ()=>{
|
||
|
let js="{let q=document.forms[0].q;q.focus();q.value=tabs.children[iTab].src}"
|
||
|
win.webContents.executeJavaScript(js,false)
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+L', click:()=>{
|
||
|
win.webContents.executeJavaScript("document.forms[0].q.select()",false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+T', click:()=>{
|
||
|
let js = "newTab();document.forms[0].q.select();switchTab(tabs.children.length-1)";
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+R', click: ()=>{
|
||
|
gredirect=null;
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+Shift+R', click: ()=>{
|
||
|
if(0==gredirects.length) return;
|
||
|
gredirect=gredirects[0];
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+W', click: ()=>{
|
||
|
win.webContents.executeJavaScript("tabClose()",false).then((r)=>{
|
||
|
if(""===r) win.close();
|
||
|
else win.setTitle(r);
|
||
|
});
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+Tab', click: ()=>{
|
||
|
let js="tabInc(1);getWinTitle()";
|
||
|
win.webContents.executeJavaScript(js,false).then((r)=>{
|
||
|
win.setTitle(r);
|
||
|
});
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+Shift+Tab', click: ()=>{
|
||
|
let js="tabDec(-1);getWinTitle()";
|
||
|
win.webContents.executeJavaScript(js,false).then((r)=>{
|
||
|
win.setTitle(r);
|
||
|
});
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+Left', click: ()=>{
|
||
|
let js="tabs.children[iTab].goBack()";
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Ctrl+Right', click: ()=>{
|
||
|
let js="tabs.children[iTab].goForward()";
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'Esc', click: ()=>{
|
||
|
let js = `{let e=document.activeElement;
|
||
|
if(e)e.blur();try{tabs.children[iTab].stopFindInPage('clearSelection')}catch(er){}}`;
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'F5', click: ()=>{
|
||
|
win.webContents.executeJavaScript("tabs.children[iTab].reload()",false);
|
||
|
}},
|
||
|
{ label: '', accelerator: 'F12', click: ()=>{
|
||
|
let js = "try{tabs.children[iTab].openDevTools()}catch(e){console.log(e)}";
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
}},
|
||
|
|
||
|
],
|
||
|
},
|
||
|
];
|
||
|
const menu = Menu.buildFromTemplate(menuTemplate);
|
||
|
Menu.setApplicationMenu(menu);
|
||
|
}
|
||
|
|
||
|
function cmdlineProcess(argv,cwd,extra){
|
||
|
let i1st = 2+extra; //index for the first query item
|
||
|
if(argv.length>i1st){
|
||
|
if(i1st+1==argv.length){//local file
|
||
|
let fname = path.join(cwd, argv[i1st]);
|
||
|
if(fs.existsSync(fname)){
|
||
|
let js = "tabs.children[iTab].src='file://"+fname+"'";
|
||
|
win.webContents.executeJavaScript(js,false);
|
||
|
win.setTitle(argv[i1st]);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
let url=argv.slice(i1st).join(" ");
|
||
|
win.webContents.executeJavaScript("handleQuery(`"+url+"`)",false);
|
||
|
win.setTitle(url);
|
||
|
}
|
||
|
}
|