diff --git a/ebrowser.md b/ebrowser.md
index 58b4da6..94889a5 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 c161700..0db5af7 100644
--- a/en/ebrowserreadme/index.html
+++ b/en/ebrowserreadme/index.html
@@ -43,12 +43,14 @@
-
-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 ).
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.
@@ -61,9 +63,11 @@
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
@@ -89,9 +93,11 @@
cache : clear cache
dns : clear dns cache
storage: clear site storage data.
+{options }
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 4b7330e..7e272fb 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 "tr" 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 2707d0f..9e5d379 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 "tr" 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 f65491b..ce9bec4 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 1b86830..d61380f 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 1301812..97d91a9 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 f131656..6ab1508 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 38f380b..9a6f731 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 5aac75b..9d6feeb 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