From 2cc5b79da443582573552ce5f99a2084b8fad4e5 Mon Sep 17 00:00:00 2001 From: James Feng Cao Date: Sat, 15 Jun 2024 11:36:06 +0800 Subject: [PATCH] updates ebrowser --- ebrowser.md | 14 ++- en/ebrowserreadme/index.html | 14 ++- en/index.xml | 4 +- en/sitemap.xml | 6 +- en/unlist/index.xml | 2 +- misc/ebrowser/index.html | 13 ++- misc/ebrowser/webview.js | 159 +++++++++++++++++++++++------------ sitemap.xml | 2 +- zh/bookmark/index.html | 2 +- zh/readme/index.html | 2 +- zh/rjs/index.html | 2 +- 11 files changed, 145 insertions(+), 75 deletions(-) diff --git a/ebrowser.md b/ebrowser.md index 58b4da60..94889a59 100644 --- a/ebrowser.md +++ b/ebrowser.md @@ -1,9 +1,11 @@ -### [Ebrowser](https://github.com/torappinfo/ebrowser) as alternative to [uweb browser](https://github.com/torappinfo/uweb) -Ebrowser is the minimal browser with the philosophy of [Android uweb browser](https://gitlab.com/jamesfengcao/uweb). +### [Ebrowser](https://github.com/torappinfo/ebrowser): keyboard-friendly minimal suckless web browser +Ebrowser is designed with the philosophy of [Android uweb browser](https://github.com/torappinfo/uweb) ([gitlab](https://gitlab.com/jamesfengcao/uweb)). - lightweight (less than 20k bytes) without bundled electron. - much less memory footprint than edge/chrome browser and highly performant. -- keyboard (command line) friendly. +- keyboard friendly with vim-style keymaps and command line support in address bar. +- global redirection to bypass censorship. +- user scripts at will. Ex. pressing "tr" to translate the page (need mapkeys.json config). - customizable. Note: Usually electron apps are heavyweight as they use browsers for simple things. Ebrowser uses core chromium effectively and very lightweight. Recommend to install electron separately. @@ -18,9 +20,11 @@ Run ebrowser electron ~/node_modules/ebrowser #### Key shortcuts +- CTRL+C: stop loading - CTRL+G: address bar to show page url - CTRL+L: focus to address bar - CTRL+T: new Tab +- CTRL+SHIFT+T: restore closed Tab - CTRL+TAB: switch to next tab - CTRL+SHIFT+TAB: switch to previous tab - CTRL+W: close Tab @@ -43,7 +47,9 @@ Run ebrowser - cache : clear cache - dns : clear dns cache - storage: clear site storage data. + - {[options](https://www.electronjs.org/docs/latest/api/session#sescleardataoptions)} - ext [extension path]: load unpacked Chrome extension. + - nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection. - nh/uh for No/Use url history. - nj/uj for No/Use external Javascript files. - nr/ur for No/Use "redirect.json" for domain redirection. @@ -81,4 +87,4 @@ The other commands are defined in "mapkeys.json", which will map keys to address OR - Adjust window width and use addressbar command line ":Pdf {}" to export vector graphics. - - Use imageMagick to convert to any other vector graphics format. \ No newline at end of file + - Use imageMagick to convert to any other vector graphics format. \ No newline at end of file diff --git a/en/ebrowserreadme/index.html b/en/ebrowserreadme/index.html index c1617000..0db5af73 100644 --- a/en/ebrowserreadme/index.html +++ b/en/ebrowserreadme/index.html @@ -43,12 +43,14 @@ -

Ebrowser as alternative to uweb browser

-

Ebrowser is the minimal browser with the philosophy of Android uweb browser.

+

Ebrowser: keyboard-friendly minimal suckless web browser

+

Ebrowser is designed with the philosophy of Android uweb browser (gitlab).

Note: Usually electron apps are heavyweight as they use browsers for simple things. Ebrowser uses core chromium effectively and very lightweight. Recommend to install electron separately.

@@ -61,9 +63,11 @@

Key shortcuts

  • ext [extension path]: load unpacked Chrome extension.
  • +
  • nc/uc : No Cookie forwarding/Use Cookie forwarding with global redirection.
  • nh/uh for No/Use url history.
  • nj/uj for No/Use external Javascript files.
  • nr/ur for No/Use "redirect.json" for domain redirection.
  • @@ -146,7 +152,7 @@ -

    Last Modified: 12 June 2024
    +

    Last Modified: 15 June 2024

    
     

    diff --git a/en/index.xml b/en/index.xml index 4b7330e1..7e272fba 100644 --- a/en/index.xml +++ b/en/index.xml @@ -6,7 +6,7 @@ Recent content on uweb browser: unlimited power Hugo en - Wed, 12 Jun 2024 13:19:32 +0800 + Sat, 15 Jun 2024 09:56:42 +0800 Text selection/processing @@ -216,7 +216,7 @@ /en/ebrowserreadme/ Mon, 01 Jan 0001 00:00:00 +0000 /en/ebrowserreadme/ - Ebrowser as alternative to uweb browser Ebrowser is the minimal browser with the philosophy of Android uweb browser. lightweight (less than 20k bytes) without bundled electron. much less memory footprint than edge/chrome browser and highly performant. keyboard (command line) friendly. customizable. Note: Usually electron apps are heavyweight as they use browsers for simple things. Ebrowser uses core chromium effectively and very lightweight. Recommend to install electron separately. Install (for Windows, MacOS and Linux) Install ebrowser with nodejs installed + Ebrowser: keyboard-friendly minimal suckless web browser Ebrowser is designed with the philosophy of Android uweb browser (gitlab). lightweight (less than 20k bytes) without bundled electron. much less memory footprint than edge/chrome browser and highly performant. keyboard friendly with vim-style keymaps and command line support in address bar. global redirection to bypass censorship. user scripts at will. Ex. pressing &quot;tr&quot; to translate the page (need mapkeys.json config). customizable. Note: Usually electron apps are heavyweight as they use browsers for simple things. diff --git a/en/sitemap.xml b/en/sitemap.xml index 2707d0fb..9e5d3792 100644 --- a/en/sitemap.xml +++ b/en/sitemap.xml @@ -71,7 +71,7 @@ /> /en/ - 2024-06-12T13:19:32+08:00 + 2024-06-15T09:56:42+08:00 /en/ebrowserreadme/ - 2024-06-12T13:19:32+08:00 + 2024-06-15T09:56:42+08:00 /en/mirrors/ 2024-04-06T10:20:49+08:00 @@ -539,7 +539,7 @@ /> /en/unlist/ - 2024-06-12T13:19:32+08:00 + 2024-06-15T09:56:42+08:00 /en/ebrowserreadme/ Mon, 01 Jan 0001 00:00:00 +0000 /en/ebrowserreadme/ - Ebrowser as alternative to uweb browser Ebrowser is the minimal browser with the philosophy of Android uweb browser. lightweight (less than 20k bytes) without bundled electron. much less memory footprint than edge/chrome browser and highly performant. keyboard (command line) friendly. customizable. Note: Usually electron apps are heavyweight as they use browsers for simple things. Ebrowser uses core chromium effectively and very lightweight. Recommend to install electron separately. Install (for Windows, MacOS and Linux) Install ebrowser with nodejs installed + Ebrowser: keyboard-friendly minimal suckless web browser Ebrowser is designed with the philosophy of Android uweb browser (gitlab). lightweight (less than 20k bytes) without bundled electron. much less memory footprint than edge/chrome browser and highly performant. keyboard friendly with vim-style keymaps and command line support in address bar. global redirection to bypass censorship. user scripts at will. Ex. pressing &quot;tr&quot; to translate the page (need mapkeys.json config). customizable. Note: Usually electron apps are heavyweight as they use browsers for simple things. diff --git a/misc/ebrowser/index.html b/misc/ebrowser/index.html index f65491b2..ce9bec44 100644 --- a/misc/ebrowser/index.html +++ b/misc/ebrowser/index.html @@ -28,7 +28,8 @@ Copyright (C) 2024 Richard Hao Cao var tabs; var engines = {}; var mapKeys = {}; - var defaultSE = "https://www.bing.com/search?q="; + var closedUrls = []; + var defaultSE = "https://www.bing.com/search?q=%s"; let lastKeys; let lastKeys_millis = 0; @@ -108,6 +109,7 @@ Copyright (C) 2024 Richard Hao Cao let nTabs = tabs.children.length; if(nTabs<2) return "";//no remain tab let tab = tabs.children[iTab]; + closedUrls.push(tab.getURL()); if(document.activeElement == tab) tab.blur(); tabs.removeChild(tab); nTabs--; @@ -210,13 +212,16 @@ Copyright (C) 2024 Richard Hao Cao } function getQ(){return document.forms[0].q.value;} function bang(query, iSpace){ + let se=defaultSE; if(iSpace>0){ let name = query.slice(0,iSpace); let engine = engines[name]; - if(engine) - return engine+query.substring(iSpace+1); + if(engine){ + se = engine; + query = query.substring(iSpace+1); + } } - return defaultSE+query; + return se.replace('%s',query); } function coloncommand(q){ document.title = q; diff --git a/misc/ebrowser/webview.js b/misc/ebrowser/webview.js index 1b86830a..d61380f2 100644 --- a/misc/ebrowser/webview.js +++ b/misc/ebrowser/webview.js @@ -2,7 +2,8 @@ */ const { app, BrowserWindow, Menu, shell, clipboard, - session, protocol, net} = require('electron') + session, protocol, net, dialog +} = require('electron') let win; if(!app.requestSingleInstanceLock()) @@ -10,7 +11,6 @@ if(!app.requestSingleInstanceLock()) else { app.on('ready', createWindow); app.on('second-instance', (event, args, cwd) => { - // 当已经有运行的实例时,我们激活窗口而不是创建新的窗口 if (win) { if (win.isMinimized()) { win.restore() @@ -34,6 +34,7 @@ var redirects; var bRedirect = true; var bJS = true; var bHistory = false; +var bForwardCookie = false; var proxies = {}; var proxy; var useragents = {}; @@ -47,14 +48,14 @@ fs.readFile(path.join(__dirname,'redirect.json'), 'utf8', (err, jsonString) => { if (err) return; try { redirects = JSON.parse(jsonString); - } catch (e){} + } catch (e){console.log(e)} }); async function createWindow () { let json = await fs.promises.readFile(path.join(__dirname,'uas.json'), 'utf8'); try { useragents = JSON.parse(json); - } catch (e){} + } catch (e){console.log(e)} await (async ()=>{ try{ @@ -65,7 +66,7 @@ async function createWindow () { for await (const line of readInterface) { addrCommand(line); } - }catch(e){return;} + }catch(e){console.log(e);} })(); win = new BrowserWindow( @@ -85,7 +86,7 @@ async function createWindow () { if (err) return; try { gredirects = JSON.parse(jsonString); - } catch (e){} + } catch (e){console.log(e)} }); fs.readFile(path.join(__dirname,'proxy.json'), 'utf8', (err, jsonString) => { @@ -97,7 +98,7 @@ async function createWindow () { } return val; }); - } catch (e){} + } catch (e){console.log(e)} }); cmdlineProcess(process.argv, process.cwd(), 0); @@ -108,7 +109,6 @@ async function createWindow () { }); win.webContents.on('console-message',cbConsoleMsg); - //protocol.handle("https",cbScheme_https); } app.on('window-all-closed', function () { @@ -154,6 +154,7 @@ function addrCommand(cmd){ return; case "clear": if(args.length==1){ + session.defaultSession.clearData(); return; } switch(args[1]){ @@ -166,11 +167,27 @@ function addrCommand(cmd){ case "storage": session.defaultSession.clearStorageData(); return; + default: + try { + let opts = JSON.parse(args.slice(1).join("")); + session.defaultSession.clearData(opts); + }catch(e){console.log(e)} } return; case "ext": session.defaultSession.loadExtension(args[1]); return; + case "nc": + bForwardCookie = false; + msgbox_info("Cookie forwarding disabled"); + return; + case "uc": + if(bForwardCookie) { + msgbox_info("Cookie forwarding enabled for global redirection"); + return; + } + forwardCookie(); + return; case "nh": bHistory = false; return; case "uh": @@ -230,37 +247,7 @@ function interceptRequest(details, callback){ 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' && + if(gredirect || !bRedirect ||(details.resourceType !== 'mainFrame' && details.resourceType !== 'subFrame')) break; let oURL = new URL(details.url); let domain = oURL.hostname; @@ -338,59 +325,71 @@ function topMenu(){ { label: '', submenu: [ - { label: '', accelerator: 'Ctrl+G', click: ()=>{ + { label: 'Stop', accelerator: 'Ctrl+C', click: ()=>{ + let js="tabs.children[iTab].stop()" + win.webContents.executeJavaScript(js,false) + }}, + { label: 'getURL', 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:()=>{ + { label: 'Select', accelerator: 'Ctrl+L', click:()=>{ win.webContents.executeJavaScript("document.forms[0].q.select()",false); }}, - { label: '', accelerator: 'Ctrl+T', click:()=>{ + { label: 'New Tab', 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: 'Restore Tab', accelerator: 'Ctrl+Shift+T', click:()=>{ + let js = "{let u=closedUrls.pop();if(u){newTab();switchTab(tabs.children.length-1);tabs.children[iTab].src=u}}"; + win.webContents.executeJavaScript(js,false); }}, - { label: '', accelerator: 'Ctrl+Shift+R', click: ()=>{ + { label: 'No redirect', accelerator: 'Ctrl+R', click: ()=>{ + if(gredirect){ + gredirect=null; + unregisterHandler(); + } + }}, + { label: 'Redirect', accelerator: 'Ctrl+Shift+R', click: ()=>{ if(0==gredirects.length) return; + if(!gredirect) registerHandler(); gredirect=gredirects[0]; }}, - { label: '', accelerator: 'Ctrl+W', click: ()=>{ + { label: 'Close', accelerator: 'Ctrl+W', click: ()=>{ win.webContents.executeJavaScript("tabClose()",false).then((r)=>{ if(""===r) win.close(); else win.setTitle(r); }); }}, - { label: '', accelerator: 'Ctrl+Tab', click: ()=>{ + { label: 'Next Tab', 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: ()=>{ + { label: 'Previous Tab', 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: ()=>{ + { label: 'Go backward', accelerator: 'Ctrl+Left', click: ()=>{ let js="tabs.children[iTab].goBack()"; win.webContents.executeJavaScript(js,false); }}, - { label: '', accelerator: 'Ctrl+Right', click: ()=>{ + { label: 'Go forward', accelerator: 'Ctrl+Right', click: ()=>{ let js="tabs.children[iTab].goForward()"; win.webContents.executeJavaScript(js,false); }}, - { label: '', accelerator: 'Esc', click: ()=>{ + { label: 'No focus', 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: ()=>{ + { label: 'Reload', accelerator: 'F5', click: ()=>{ win.webContents.executeJavaScript("tabs.children[iTab].reload()",false); }}, - { label: '', accelerator: 'F12', click: ()=>{ + { label: 'Devtools', accelerator: 'F12', click: ()=>{ let js = "try{tabs.children[iTab].openDevTools()}catch(e){console.log(e)}"; win.webContents.executeJavaScript(js,false); }}, @@ -419,3 +418,57 @@ function cmdlineProcess(argv,cwd,extra){ win.setTitle(url); } } + +async function cbScheme_redir(req){ + if(!gredirect) return null; + let oUrl = req.url; + let newurl = gredirect+oUrl; + let options = { + body: req.body, + headers: req.headers, + method: req.method, + referer: req.referer, + duplex: "half", + bypassCustomProtocolHandlers: true + }; + if(bForwardCookie){ + let cookies = await session.defaultSession.cookies.get({url: oUrl}); + let cookieS = cookies.map (cookie => cookie.name + '=' + cookie.value ).join(';'); + options.headers['Cookie'] = cookieS; + } + + return fetch(newurl, options); +} + +function registerHandler(){ + protocol.handle("http",cbScheme_redir); + protocol.handle("https",cbScheme_redir); + protocol.handle("ws",cbScheme_redir); + protocol.handle("wss",cbScheme_redir); +} +function unregisterHandler(){ + protocol.unhandle("http",cbScheme_redir); + protocol.unhandle("https",cbScheme_redir); + protocol.unhandle("ws",cbScheme_redir); + protocol.unhandle("wss",cbScheme_redir); +} + +function forwardCookie(){ + const choice = dialog.showMessageBoxSync(null, { + type: 'warning', + title: 'Confirm cookie forwarding with global redirection', + message: 'Cookies are used to access your account. Forwarding cookies is vulnerable to global redirection server, proceed to enable cookie forwarding with global redirection?', + buttons: ['No','Yes'] + }) + if(1===choice) bForwardCookie=true; +} +function msgbox_info(msg){ + dialog.showMessageBoxSync(null, { + type: 'info', + title: msg, + message: msg, + buttons: ['OK'] + }) +} + + diff --git a/sitemap.xml b/sitemap.xml index 1301812a..97d91a95 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -4,7 +4,7 @@ /en/sitemap.xml - 2024-06-12T13:19:32+08:00 + 2024-06-15T09:56:42+08:00 diff --git a/zh/bookmark/index.html b/zh/bookmark/index.html index f131656c..6ab1508e 100644 --- a/zh/bookmark/index.html +++ b/zh/bookmark/index.html @@ -78,7 +78,7 @@ AI/chatGPT:

    Last Modified: 12 June 2024
    -remove google translation in China
    +markdown rjs to use marked

    
     

    diff --git a/zh/readme/index.html b/zh/readme/index.html index 38f380b6..9a6f7316 100644 --- a/zh/readme/index.html +++ b/zh/readme/index.html @@ -120,7 +120,7 @@

    Last Modified: 13 June 2024
    -remove google translation in China
    +markdown rjs to use marked

    
     

    diff --git a/zh/rjs/index.html b/zh/rjs/index.html index 5aac75b9..9d6feeb1 100644 --- a/zh/rjs/index.html +++ b/zh/rjs/index.html @@ -72,7 +72,7 @@

    Last Modified: 13 June 2024
    -remove google translation in China
    +markdown rjs to use marked