2024-06-13 00:07:31 +00:00
/ * C o p y r i g h t ( C ) 2 0 2 4 R i c h a r d H a o C a o
2024-06-24 01:58:02 +00:00
Ebrowser is free software : you can redistribute it and / or modify it under the terms of the GNU General Public License as published by the Free Software Foundation , either version 3 of the License , or ( at your option ) any later version .
Ebrowser is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License along with this program . If not , see < https : //www.gnu.org/licenses/>.
* /
2024-06-11 10:42:38 +00:00
const {
app , BrowserWindow , Menu , shell , clipboard ,
2024-07-01 02:11:01 +00:00
session , protocol , net , dialog , ipcMain
2024-06-15 03:36:06 +00:00
} = require ( 'electron' )
2024-06-11 10:42:38 +00:00
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 ( ) ;
} )
}
2024-06-27 12:10:33 +00:00
var translateRes ;
{
let langs = app . getPreferredSystemLanguages ( ) ;
if ( langs . length == 0 || langs [ 0 ] . startsWith ( 'en' ) || ! initTranslateRes ( langs [ 0 ] ) )
topMenu ( ) ;
else
Menu . setApplicationMenu ( null ) ;
}
2024-06-11 10:42:38 +00:00
2024-06-24 01:58:02 +00:00
var repositoryurl = "https://gitlab.com/jamesfengcao/uweb/-/raw/master/misc/ebrowser/" ;
2024-06-11 10:42:38 +00:00
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 ;
2024-06-15 03:36:06 +00:00
var bForwardCookie = false ;
2024-06-11 10:42:38 +00:00
var proxies = { } ;
var proxy ;
var useragents = { } ;
2024-06-30 09:04:50 +00:00
var downloadMenus ; //[]
2024-06-11 10:42:38 +00:00
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 ;
fs . readFile ( path . join ( _ _dirname , 'redirect.json' ) , 'utf8' , ( err , jsonString ) => {
if ( err ) return ;
try {
redirects = JSON . parse ( jsonString ) ;
2024-06-15 03:36:06 +00:00
} catch ( e ) { console . log ( e ) }
2024-06-11 10:42:38 +00:00
} ) ;
async function createWindow ( ) {
try {
2024-06-19 14:41:21 +00:00
let json = await fs . promises . readFile ( path . join ( _ _dirname , 'uas.json' ) , 'utf8' ) ;
2024-06-11 10:42:38 +00:00
useragents = JSON . parse ( json ) ;
2024-06-15 03:36:06 +00:00
} catch ( e ) { console . log ( e ) }
2024-06-11 10:42:38 +00:00
await ( async ( ) => {
try {
const readInterface = readline . createInterface ( {
input : fs . createReadStream ( path . join ( _ _dirname , 'config' ) , 'utf8' ) ,
} ) ;
for await ( const line of readInterface ) {
addrCommand ( line ) ;
}
2024-06-15 03:36:06 +00:00
} catch ( e ) { console . log ( e ) ; }
2024-06-11 10:42:38 +00:00
} ) ( ) ;
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 ) ;
2024-06-15 03:36:06 +00:00
} catch ( e ) { console . log ( e ) }
2024-06-11 10:42:38 +00:00
} ) ;
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 ;
} ) ;
2024-06-15 03:36:06 +00:00
} catch ( e ) { console . log ( e ) }
2024-06-11 10:42:38 +00:00
} ) ;
cmdlineProcess ( process . argv , process . cwd ( ) , 0 ) ;
//app.commandLine.appendSwitch ('trace-warnings');
2024-06-30 09:04:50 +00:00
fs . readFile ( path . join ( _ _dirname , 'download.json' ) , 'utf8' , ( err , jsonStr ) => {
if ( err ) return ;
try {
downloadMenus = JSON . parse ( jsonStr ) ;
} catch ( e ) { console . log ( e ) }
} ) ;
2024-06-11 10:42:38 +00:00
win . webContents . on ( 'page-title-updated' , ( event , cmd ) => {
addrCommand ( cmd ) ;
} ) ;
2024-06-30 09:04:50 +00:00
session . defaultSession . on ( "will-download" , ( e , item ) => {
//item.setSavePath(save)
if ( ! downloadMenus ) return ;
let buttons = [ "OK" , "Cancel" , translate ( "Copy" ) ] ;
buttons . push ( downloadMenus . filter ( ( item , index ) => ( index & 1 ) === 0 ) ) ;
const button = dialog . showMessageBoxSync ( mainWindow , {
"type" : "question" ,
"title" : translate ( "Download" ) ,
"message" : ` Do you want to download the file? ` ,
"buttons" : buttons ,
"defaultId" : 0 ,
} ) ;
switch ( button ) {
case 0 :
return ;
case 1 :
break ;
case 2 :
clipboard . writeText ( item . getURL ( ) ) ;
break ;
default :
let cmd = downloadMenus [ 2 * button - 5 ] . replace ( '%u' , item . getURL ( ) ) ;
let js = ` handleQuery( \` ${ cmd } \` ) ` ;
win . webContents . executeJavaScript ( js , false ) ;
}
e . preventDefault ( ) ;
} ) ;
2024-06-11 10:42:38 +00:00
win . webContents . on ( 'console-message' , cbConsoleMsg ) ;
}
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 ) ;
2024-06-24 22:06:51 +00:00
//contents.on('did-finish-load',()=>{cbFinishLoad(contents)});
2024-06-11 10:42:38 +00:00
}
} ) ;
2024-07-01 02:11:01 +00:00
ipcMain . on ( 'command' , ( event , cmd ) => {
addrCommand ( cmd ) ;
} ) ;
2024-06-11 10:42:38 +00:00
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 ) {
2024-06-15 03:36:06 +00:00
session . defaultSession . clearData ( ) ;
2024-06-11 10:42:38 +00:00
return ;
}
switch ( args [ 1 ] ) {
case "cache" :
session . defaultSession . clearCache ( ) ;
return ;
case "dns" :
session . defaultSession . clearHostResolverCache ( ) ;
return ;
case "storage" :
session . defaultSession . clearStorageData ( ) ;
return ;
2024-06-15 03:36:06 +00:00
default :
try {
let opts = JSON . parse ( args . slice ( 1 ) . join ( "" ) ) ;
session . defaultSession . clearData ( opts ) ;
} catch ( e ) { console . log ( e ) }
2024-06-11 10:42:38 +00:00
}
return ;
case "ext" :
session . defaultSession . loadExtension ( args [ 1 ] ) ;
return ;
2024-06-18 15:28:12 +00:00
case "gr" :
if ( args . length < 2 ) {
gredirect _enable ( 0 ) ;
return ;
}
let i = parseInt ( args [ 1 ] ) ;
if ( i >= 0 && i < gredirects . length )
gredirect _enable ( i ) ;
else
gredirect _disable ( ) ;
return ;
2024-06-24 22:06:51 +00:00
case "js" : //execute js
2024-06-19 13:58:58 +00:00
eval ( cmd . slice ( 4 ) ) ;
return ;
2024-06-15 03:36:06 +00:00
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 ;
2024-06-11 10:42:38 +00:00
case "np" :
session . defaultSession . setProxy ( { mode : "direct" } ) ;
2024-06-18 02:41:17 +00:00
bRedirect = true ;
2024-06-11 10:42:38 +00:00
return ;
case "up" :
if ( args . length > 1 )
proxy = proxies [ args [ 1 ] ] ; //retrieve proxy
2024-06-18 02:41:17 +00:00
if ( proxy ) {
2024-06-18 15:28:12 +00:00
gredirect _disable ( ) ;
2024-06-11 10:42:38 +00:00
session . defaultSession . setProxy ( proxy ) ;
2024-06-18 02:41:17 +00:00
}
2024-06-11 10:42:38 +00:00
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 ;
2024-06-18 15:28:12 +00:00
case "update" :
let updateurl ;
if ( 1 == args . length )
2024-06-30 09:04:50 +00:00
updateApp ( repositoryurl ) ;
2024-06-18 15:28:12 +00:00
else {
2024-06-30 09:04:50 +00:00
filename = args [ 1 ] ;
let iSlash = filename . lastIndexOf ( '/' ) ;
if ( iSlash > 0 ) {
let folder = path . join ( _ _dirname , filename . substring ( 0 , iSlash ) ) ;
fs . mkdirSync ( folder , { recursive : true } ) ;
}
fetch2file ( repositoryurl , filename ) ;
2024-06-18 15:28:12 +00:00
}
return ;
2024-06-11 10:42:38 +00:00
}
}
}
2024-06-18 15:28:12 +00:00
function gredirect _disable ( ) {
if ( gredirect ) {
gredirect = null ;
unregisterHandler ( ) ;
}
bRedirect = false ;
}
function gredirect _enable ( i ) {
if ( i >= gredirects . length ) return ;
if ( ! gredirect ) registerHandler ( ) ;
gredirect = gredirects [ i ] ;
}
2024-06-11 10:42:38 +00:00
function cbConsoleMsg ( e , level , msg , line , sourceid ) {
console . log ( line ) ;
console . log ( sourceid ) ;
console . log ( msg ) ;
}
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 {
2024-06-15 03:36:06 +00:00
if ( gredirect || ! bRedirect || ( details . resourceType !== 'mainFrame' &&
2024-06-11 10:42:38 +00:00
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 = [
{
2024-06-30 09:04:50 +00:00
label : labelprefix + translate ( 'Open' ) ,
2024-06-11 10:42:38 +00:00
click : ( ) => {
shell . openExternal ( linkUrl ) ;
}
} ,
{
2024-06-30 09:04:50 +00:00
label : labelprefix + translate ( 'Copy' ) ,
2024-06-11 10:42:38 +00:00
click : ( ) => {
clipboard . writeText ( linkUrl ) ;
}
} ,
{
2024-06-30 09:04:50 +00:00
label : labelprefix + translate ( 'Download' ) ,
2024-06-11 10:42:38 +00:00
click : ( ) => {
win . contentView . children [ i ] . webContents . downloadURL ( linkUrl ) ;
}
} ,
] ;
2024-06-30 09:04:50 +00:00
if ( downloadMenus ) {
for ( let i = 0 ; i < downloadMenus . length - 1 ; i ++ ) {
menuTemplate . push ( {
label : labelprefix + downloadMenus [ i ] ,
click : ( ) => {
let cmd = downloadMenus [ i + 1 ] . replace ( '%u' , linkUrl ) ;
let js = ` handleQuery( \` ${ cmd } \` ) ` ;
win . webContents . executeJavaScript ( js , false ) ;
}
} ) ;
}
}
2024-06-11 10:42:38 +00:00
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 = [
2024-06-19 07:48:13 +00:00
{
2024-06-27 12:10:33 +00:00
label : translate ( 'Edit' ) ,
2024-06-19 07:48:13 +00:00
submenu : [
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Config folder' ) , click : ( ) => {
2024-06-19 07:48:13 +00:00
shell . openPath ( _ _dirname ) ;
} } ,
]
} ,
2024-06-11 10:42:38 +00:00
{
2024-06-27 12:10:33 +00:00
label : translate ( 'Help' ) ,
2024-06-11 10:42:38 +00:00
submenu : [
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Check for updates' ) , click : ( ) => {
2024-06-18 22:36:48 +00:00
addrCommand ( ":update" ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Help' ) , accelerator : 'F1' , click : ( ) => {
2024-06-19 07:25:23 +00:00
help ( ) ;
2024-06-18 02:41:17 +00:00
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Stop' ) , accelerator : 'Ctrl+C' , click : ( ) => {
2024-06-15 03:36:06 +00:00
let js = "tabs.children[iTab].stop()"
win . webContents . executeJavaScript ( js , false )
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'getURL' ) , accelerator : 'Ctrl+G' , click : ( ) => {
2024-06-24 22:06:51 +00:00
let js = "{let q=document.forms[0].q;q.focus();q.value=tabs.children[iTab].getURL()}"
2024-06-11 10:42:38 +00:00
win . webContents . executeJavaScript ( js , false )
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Select' ) , accelerator : 'Ctrl+L' , click : ( ) => {
2024-06-11 10:42:38 +00:00
win . webContents . executeJavaScript ( "document.forms[0].q.select()" , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'New Tab' ) , accelerator : 'Ctrl+T' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = "newTab();document.forms[0].q.select();switchTab(tabs.children.length-1)" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Restore Tab' ) , accelerator : 'Ctrl+Shift+T' , click : ( ) => {
2024-06-15 03:36:06 +00:00
let js = "{let u=closedUrls.pop();if(u){newTab();switchTab(tabs.children.length-1);tabs.children[iTab].src=u}}" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'No redirect' ) , accelerator : 'Ctrl+R' , click : ( ) => {
2024-06-18 15:28:12 +00:00
gredirect _disable ( ) ;
2024-06-11 10:42:38 +00:00
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Redirect' ) , accelerator : 'Ctrl+Shift+R' , click : ( ) => {
2024-06-18 15:28:12 +00:00
gredirect _enable ( 0 ) ;
2024-06-11 10:42:38 +00:00
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Close tab' ) , accelerator : 'Ctrl+W' , click : ( ) => {
2024-06-11 10:42:38 +00:00
win . webContents . executeJavaScript ( "tabClose()" , false ) . then ( ( r ) => {
if ( "" === r ) win . close ( ) ;
else win . setTitle ( r ) ;
} ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Next Tab' ) , accelerator : 'Ctrl+Tab' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = "tabInc(1);getWinTitle()" ;
win . webContents . executeJavaScript ( js , false ) . then ( ( r ) => {
win . setTitle ( r ) ;
} ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Previous Tab' ) , accelerator : 'Ctrl+Shift+Tab' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = "tabDec(-1);getWinTitle()" ;
win . webContents . executeJavaScript ( js , false ) . then ( ( r ) => {
win . setTitle ( r ) ;
} ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Go backward' ) , accelerator : 'Alt+Left' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = "tabs.children[iTab].goBack()" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Go forward' ) , accelerator : 'Alt+Right' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = "tabs.children[iTab].goForward()" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Zoom in' ) , accelerator : 'Ctrl+Shift+=' , click : ( ) => {
2024-06-18 02:41:17 +00:00
let js = "{let t=tabs.children[iTab];let s=t.getZoomFactor()*1.2;t.setZoomFactor(s)}" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Zoom out' ) , accelerator : 'Ctrl+-' , click : ( ) => {
2024-06-18 02:41:17 +00:00
let js = "{let t=tabs.children[iTab];let s=t.getZoomFactor()/1.2;t.setZoomFactor(s)}" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Default zoom' ) , accelerator : 'Ctrl+0' , click : ( ) => {
2024-06-18 02:41:17 +00:00
let js = "tabs.children[iTab].setZoomFactor(1)" ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'No focus' ) , accelerator : 'Esc' , click : ( ) => {
2024-06-11 10:42:38 +00:00
let js = ` {let e=document.activeElement;
if ( e ) e . blur ( ) ; try { tabs . children [ iTab ] . stopFindInPage ( 'clearSelection' ) } catch ( er ) { } } ` ;
win . webContents . executeJavaScript ( js , false ) ;
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Reload' ) , accelerator : 'F5' , click : ( ) => {
2024-06-26 01:14:24 +00:00
win . webContents . executeJavaScript ( "tabs.children[iTab].reload()" , false ) ;
2024-06-11 10:42:38 +00:00
} } ,
2024-06-27 12:10:33 +00:00
{ label : translate ( 'Devtools' ) , accelerator : 'F12' , click : ( ) => {
2024-06-11 10:42:38 +00:00
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 ) ;
}
}
2024-06-15 03:36:06 +00:00
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' ]
} )
}
2024-06-18 15:28:12 +00:00
async function updateApp ( url ) { //url must ending with "/"
let msg ;
do {
try {
let res = await fetch ( url + "package.json" ) ;
let packageS = await res . text ( ) ;
2024-06-18 22:36:48 +00:00
{ //the last part of version string is the version number, must keep increasing
2024-06-18 15:28:12 +00:00
let head = packageS . slice ( 2 , 40 ) ;
let iV = head . indexOf ( "version" ) ;
if ( iV < 0 ) {
msg = "remote package.json corrupted"
break ;
}
2024-06-19 07:25:23 +00:00
iV = iV + 10 ;
2024-06-18 15:28:12 +00:00
let iE = head . indexOf ( '"' , iV + 4 ) ;
let iS = head . lastIndexOf ( '.' , iE - 1 ) ;
2024-06-18 22:36:48 +00:00
let nLatestVer = parseInt ( head . substring ( iS + 1 , iE ) ) ;
2024-06-18 15:45:21 +00:00
let ver = app . getVersion ( ) ;
2024-06-18 22:36:48 +00:00
iS = ver . lastIndexOf ( '.' ) ;
let nVer = parseInt ( ver . substring ( iS + 1 ) ) ;
if ( nVer >= nLatestVer ) {
msg = ` Current version ${ ver } is already up to date ` ;
break ;
}
const choice = dialog . showMessageBoxSync ( null , {
type : 'warning' ,
title : ` Update from ${ url } ` ,
message : ` Proceed to update from ${ ver } to ${ head . substring ( iV , iE ) } ? ` ,
buttons : [ 'YES' , 'NO' ]
} ) ;
if ( 1 === choice ) return ;
2024-06-18 15:28:12 +00:00
}
2024-06-18 22:36:48 +00:00
2024-06-18 15:28:12 +00:00
writeFile ( "package.json" , packageS ) ;
fetch2file ( url , "webview.js" ) ;
fetch2file ( url , "index.html" ) ;
msg = "Update completed" ;
} catch ( e ) {
msg = "Fail to update"
}
} while ( false ) ;
dialog . showMessageBoxSync ( null , {
type : 'info' ,
2024-06-18 22:36:48 +00:00
title : ` Update from ${ url } ` ,
2024-06-18 15:28:12 +00:00
message : msg ,
buttons : [ 'OK' ]
} )
}
2024-06-19 13:58:58 +00:00
async function fetch2file ( urlFolder , filename , bOverwritten = true ) {
let pathname = path . join ( _ _dirname , filename ) ;
if ( ! bOverwritten && fs . existsSync ( pathname ) ) return ;
2024-06-18 15:28:12 +00:00
let res = await fetch ( urlFolder + filename ) ;
let str = await res . text ( ) ;
2024-06-19 13:58:58 +00:00
writeFile ( pathname , str ) ;
2024-06-18 15:28:12 +00:00
}
2024-06-15 03:36:06 +00:00
2024-06-18 15:28:12 +00:00
async function writeFile ( filename , str ) {
2024-06-19 13:58:58 +00:00
let pathname = filename + ".new" ;
2024-06-18 15:28:12 +00:00
fs . writeFile ( pathname , str , ( err ) => {
if ( err ) throw "Fail to write" ;
2024-06-19 13:58:58 +00:00
fs . rename ( pathname , filename , ( e1 ) => {
2024-06-18 15:28:12 +00:00
if ( e1 ) throw "Fail to rename" ;
} ) ;
} ) ;
}
2024-06-19 13:58:58 +00:00
2024-06-19 07:25:23 +00:00
function help ( ) {
const readme = "README.md" ;
2024-06-24 22:06:51 +00:00
const htmlFN = path . join ( _ _dirname , readme ) ;
let js = ` {let t=tabs.children[iTab];t.dataset.jsonce=BML_md;t.src="file:// ${ htmlFN } "} ` ;
2024-06-19 07:25:23 +00:00
win . webContents . executeJavaScript ( js , false )
}
2024-06-27 12:10:33 +00:00
function initTranslateRes ( lang ) {
let basename = path . join ( _ _dirname , "translate." ) ;
let fname = basename + lang ;
if ( ! fs . existsSync ( fname ) )
fname = basename + lang . slice ( 0 , 2 ) ;
if ( ! fs . existsSync ( fname ) ) return false ;
( async ( ) => {
try {
let json = await fs . promises . readFile ( fname , 'utf8' ) ;
translateRes = JSON . parse ( json ) ;
} catch ( e ) { }
topMenu ( ) ;
} ) ( ) ;
return true ;
}
function translate ( str ) {
let result ;
if ( translateRes && ( result = translateRes [ str ] ) ) return result ;
return str ;
}