2022-09-01 20:38:13 +08:00
import fs from 'fs' ;
import tmp from 'tmp' ;
import { app , powerMonitor , BrowserWindow , Tray , Menu , ipcMain , clipboard , shell , nativeImage , dialog } from 'electron' ;
import windowStateKeeper from 'electron-window-state' ;
import AutoLaunch from 'auto-launch' ;
import { autoUpdater } from 'electron-updater' ;
import axios from 'axios' ;
import pkg from './package.json' ;
let forceQuit = false ;
let downloading = false ;
let mainWindow ;
let tray ;
let settings = { } ;
let isFullScreen = false ;
let isWin = process . platform === 'win32' ;
let isOsx = process . platform === 'darwin' ;
let isSuspend = false ;
let userData = app . getPath ( 'userData' ) ;
let imagesCacheDir = ` ${ userData } /images ` ;
let voicesCacheDir = ` ${ userData } /voices ` ;
let mainMenu = [
{
label : pkg . name ,
submenu : [
{
label : ` About ${ pkg . name } ` ,
selector : 'orderFrontStandardAboutPanel:' ,
} ,
{
2022-09-02 09:52:16 +08:00
label : '首选项...' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+,' : 'Cmd+,' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-settings' ) ;
}
} ,
{
label : 'messageInput' ,
accelerator : 'Esc' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-messageInput' ) ;
}
} ,
{
type : 'separator'
} ,
{
role : 'hide'
} ,
{
role : 'hideothers'
} ,
{
role : 'unhide'
} ,
{
2022-09-02 10:01:41 +08:00
label : '检查更新' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+U' : 'Cmd+U' ,
click ( ) {
2022-09-02 10:01:41 +08:00
shell . openExternal ( 'spk://store/chat/wewechat' ) ;
2022-09-01 20:38:13 +08:00
}
} ,
{
type : 'separator'
} ,
{
label : 'Quit weweChat' ,
accelerator : ! isOsx ? 'Alt+Q' : 'Command+Q' ,
selector : 'terminate:' ,
click ( ) {
forceQuit = true ;
mainWindow = null ;
app . quit ( ) ;
}
}
]
} ,
{
label : 'File' ,
submenu : [
{
label : 'New Chat' ,
accelerator : ! isOsx ? 'Ctrl+N' : 'Cmd+N' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-newchat' ) ;
}
} ,
{
label : 'Search...' ,
accelerator : ! isOsx ? 'Ctrl+F' : 'Cmd+F' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-search' ) ;
}
} ,
{
label : 'Batch Send Message' ,
accelerator : ! isOsx ? 'Ctrl+B' : 'Cmd+B' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-batchsend' ) ;
}
} ,
{
type : 'separator' ,
} ,
{
label : 'Insert emoji' ,
accelerator : ! isOsx ? 'Ctrl+I' : 'Cmd+I' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-emoji' ) ;
}
} ,
{
type : 'separator' ,
} ,
{
label : 'Next conversation' ,
accelerator : ! isOsx ? 'Ctrl+J' : 'Cmd+J' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-next' ) ;
}
} ,
{
label : 'Previous conversation' ,
accelerator : ! isOsx ? 'Ctrl+K' : 'Cmd+K' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-previous' ) ;
}
} ,
]
} ,
{
2022-09-02 09:40:28 +08:00
label : '群聊' ,
2022-09-01 20:38:13 +08:00
submenu : [
{
label : 'Loading...' ,
}
] ,
} ,
{
2022-09-02 09:40:28 +08:00
label : '私聊' ,
2022-09-01 20:38:13 +08:00
submenu : [
{
label : 'Loading...' ,
}
] ,
} ,
{
} ,
{
label : 'Edit' ,
submenu : [
{
role : 'undo'
} ,
{
role : 'redo'
} ,
{
type : 'separator'
} ,
{
role : 'cut'
} ,
{
role : 'copy'
} ,
{
role : 'paste'
} ,
{
role : 'pasteandmatchstyle'
} ,
{
role : 'delete'
} ,
{
role : 'selectall'
}
]
} ,
{
label : 'View' ,
submenu : [
{
label : isFullScreen ? 'Exit Full Screen' : 'Enter Full Screen' ,
accelerator : ! isOsx ? 'Ctrl+Shift+F' : 'Shift+Cmd+F' ,
click ( ) {
isFullScreen = ! isFullScreen ;
mainWindow . show ( ) ;
mainWindow . setFullScreen ( isFullScreen ) ;
}
} ,
{
2022-09-02 09:52:16 +08:00
label : '显示群聊' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+Shift+M' : 'Shift+Cmd+M' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-conversations' ) ;
}
} ,
{
type : 'separator' ,
} ,
{
label : ''
} ,
{
type : 'separator' ,
} ,
{
role : 'toggledevtools'
} ,
{
role : 'togglefullscreen'
}
]
} ,
{
role : 'window' ,
submenu : [
{
role : 'minimize'
} ,
{
role : 'close'
}
]
} ,
{
role : 'help' ,
submenu : [
{
label : '反馈(不一定解决)' ,
click ( ) {
2022-09-01 21:05:47 +08:00
shell . openExternal ( 'https://gitee.com/spark-community-works-collections/wewechat-plus-plus/issues' ) ;
2022-09-01 20:38:13 +08:00
}
} ,
{
2022-09-02 09:52:16 +08:00
label : '在Gitee主页查看' ,
2022-09-01 20:38:13 +08:00
click ( ) {
2022-09-01 21:05:47 +08:00
shell . openExternal ( 'https://gitee.com/spark-community-works-collections/wewechat-plus-plus' ) ;
2022-09-01 20:38:13 +08:00
}
} ,
]
}
] ;
let trayMenu = [
{
2022-09-02 09:52:16 +08:00
label : ` 您有0条未读消息 ` ,
2022-09-01 20:38:13 +08:00
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-messages' ) ;
}
} ,
{
2022-09-02 09:52:16 +08:00
label : '打开主窗口' ,
2022-09-01 20:38:13 +08:00
click ( ) {
let isVisible = mainWindow . isVisible ( ) ;
isVisible ? mainWindow . hide ( ) : mainWindow . show ( ) ;
}
} ,
{
type : 'separator'
} ,
{
2022-09-02 09:52:16 +08:00
label : '首选项...' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+,' : 'Cmd+,' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-settings' ) ;
}
} ,
{
2022-09-02 09:52:16 +08:00
label : '在Gitee主页查看' ,
2022-09-01 20:38:13 +08:00
click ( ) {
2022-09-01 21:05:47 +08:00
shell . openExternal ( 'https://gitee.com/spark-community-works-collections/wewechat-plus-plus' ) ;
2022-09-01 20:38:13 +08:00
}
} ,
{
type : 'separator'
} ,
{
2022-09-02 09:52:16 +08:00
label : '打开开发者工具' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+Alt+I' : 'Alt+Command+I' ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . toggleDevTools ( ) ;
}
} ,
{
2022-09-02 09:52:16 +08:00
label : '隐藏菜单栏图标' ,
2022-09-01 20:38:13 +08:00
click ( ) {
mainWindow . webContents . send ( 'hide-tray' ) ;
}
} ,
{
type : 'separator'
} ,
{
2022-09-02 10:01:41 +08:00
label : '检查更新' ,
2022-09-01 20:38:13 +08:00
accelerator : ! isOsx ? 'Ctrl+U' : 'Cmd+U' ,
click ( ) {
checkForUpdates ( ) ;
}
} ,
{
label : 'Quit weweChat' ,
accelerator : ! isOsx ? 'Alt+Q' : 'Command+Q' ,
selector : 'terminate:' ,
click ( ) {
forceQuit = true ;
mainWindow = null ;
app . quit ( ) ;
}
}
] ;
let avatarPath = tmp . dirSync ( ) ;
let avatarCache = { } ;
let avatarPlaceholder = ` ${ _ _dirname } /src/assets/images/user-fallback.png ` ;
const icon = ` ${ _ _dirname } /src/assets/images/dock.png ` ;
async function getIcon ( cookies , userid , src ) {
var cached = avatarCache [ userid ] ;
var icon ;
if ( cached ) {
return cached ;
}
if ( cookies && src ) {
try {
let response = await axios ( {
url : src ,
method : 'get' ,
responseType : 'arraybuffer' ,
headers : {
Cookie : cookies ,
'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8' ,
} ,
} ) ;
// eslint-disable-next-line
let base64 = new Buffer ( response . data , 'binary' ) . toString ( 'base64' ) ;
icon = ` ${ avatarPath . name } / ${ userid } .jpg ` ;
fs . writeFileSync ( icon , base64 . replace ( /^data:image\/png;base64,/ , '' ) , 'base64' ) ;
} catch ( ex ) {
console . error ( ex ) ;
icon = avatarPlaceholder ;
}
}
var image = nativeImage . createFromPath ( icon ) ;
image = image . resize ( { width : 24 , height : 24 } ) ;
avatarCache [ userid ] = image ;
return image ;
}
function checkForUpdates ( ) {
if ( downloading ) {
dialog . showMessageBox ( {
type : 'info' ,
buttons : [ 'OK' ] ,
title : pkg . name ,
message : ` Downloading... ` ,
detail : ` Please leave the app open, the new version is downloading. You'll receive a new dialog when downloading is finished. `
} ) ;
return ;
}
autoUpdater . checkForUpdates ( ) ;
}
function updateTray ( unread = 0 ) {
if ( ! isOsx ) {
// Always show the tray icon on windows
settings . showOnTray = true ;
}
// Update unread mesage count
2022-09-02 09:52:16 +08:00
trayMenu [ 0 ] . label = ` 您有 ${ unread } 条未读消息 ` ;
2022-09-01 20:38:13 +08:00
if ( settings . showOnTray ) {
if ( tray
&& updateTray . lastUnread === unread ) {
return ;
}
let contextmenu = Menu . buildFromTemplate ( trayMenu ) ;
let icon = unread
? ` ${ _ _dirname } /src/assets/images/icon-new-message.png `
: ` ${ _ _dirname } /src/assets/images/icon.png `
;
// Make sure the last tray has been destroyed
setTimeout ( ( ) => {
if ( ! tray ) {
// Init tray icon
tray = new Tray ( icon ) ;
tray . on ( 'right-click' , ( ) => {
tray . popUpContextMenu ( ) ;
} ) ;
let clicked = false ;
tray . on ( 'click' , ( ) => {
if ( clicked ) {
mainWindow . show ( ) ;
clicked = false ;
} else {
clicked = true ;
setTimeout ( ( ) => {
clicked = false ;
} , 400 ) ;
}
} ) ;
}
tray . setImage ( icon ) ;
tray . setContextMenu ( contextmenu ) ;
} ) ;
} else {
if ( ! tray ) return ;
tray . destroy ( ) ;
tray = null ;
}
// Avoid tray icon been recreate
updateTray . lastUnread = unread ;
}
async function autostart ( ) {
var launcher = new AutoLaunch ( {
name : 'weweChat' ,
path : '/Applications/wewechat.app' ,
} ) ;
if ( settings . startup ) {
if ( ! isOsx ) {
mainWindow . webContents . send ( 'show-errors' , {
message : 'Currently only supports the OSX.'
} ) ;
return ;
}
launcher . enable ( )
. catch ( ex => {
console . error ( ex ) ;
} ) ;
} else {
launcher . disable ( ) ;
}
}
function createMenu ( ) {
var menu = Menu . buildFromTemplate ( mainMenu ) ;
if ( isOsx ) {
Menu . setApplicationMenu ( menu ) ;
} else {
mainWindow . setMenu ( menu ) ;
}
}
const createMainWindow = ( ) => {
var mainWindowState = windowStateKeeper ( {
defaultWidth : 745 ,
defaultHeight : 450 ,
} ) ;
mainWindow = new BrowserWindow ( {
x : mainWindowState . x ,
y : mainWindowState . y ,
minWidth : 745 ,
minHeight : 450 ,
transparent : true ,
titleBarStyle : 'hiddenInset' ,
backgroundColor : 'none' ,
resizable : true ,
webPreferences : {
scrollBounce : true
} ,
frame : ! isWin ,
icon
} ) ;
// mainWindow.webContents.openDevTools();
mainWindow . setSize ( 350 , 460 ) ;
mainWindow . loadURL (
` file:// ${ _ _dirname } /src/index.html `
) ;
mainWindow . webContents . on ( 'did-finish-load' , ( ) => {
try {
mainWindow . show ( ) ;
mainWindow . focus ( ) ;
} catch ( ex ) { }
} ) ;
mainWindow . webContents . on ( 'new-window' , ( event , url ) => {
event . preventDefault ( ) ;
shell . openExternal ( url ) ;
} ) ;
mainWindow . on ( 'close' , e => {
if ( forceQuit ) {
mainWindow = null ;
app . quit ( ) ;
} else {
e . preventDefault ( ) ;
mainWindow . hide ( ) ;
}
} ) ;
ipcMain . on ( 'settings-apply' , ( event , args ) => {
settings = args . settings ;
mainWindow . setAlwaysOnTop ( ! ! settings . alwaysOnTop ) ;
try {
updateTray ( ) ;
autostart ( ) ;
} catch ( ex ) {
console . error ( ex ) ;
}
} ) ;
ipcMain . on ( 'show-window' , event => {
if ( ! mainWindow . isVisible ( ) ) {
mainWindow . show ( ) ;
mainWindow . focus ( ) ;
}
} ) ;
ipcMain . on ( 'menu-update' , async ( event , args ) => {
var { cookies , contacts = [ ] , conversations = [ ] } = args ;
2022-09-02 09:40:28 +08:00
var conversationsMenu = mainMenu . find ( e => e . label === '群聊' ) ;
var contactsMenu = mainMenu . find ( e => e . label === '私聊' ) ;
2022-09-01 20:38:13 +08:00
var shouldUpdate = false ;
// if (!isOsx) {
// return;
// }
if ( conversations . length
&& conversations . map ( e => e . name ) . join ( ) !== conversationsMenu . submenu . map ( e => e . label ) . join ( ) ) {
shouldUpdate = true ;
conversations = await Promise . all (
conversations . map ( async ( e , index ) => {
let icon = await getIcon ( cookies , e . id , e . avatar ) ;
return {
label : e . name ,
accelerator : ! isOsx ? ` Ctrl+ ${ index } ` : ` Cmd+ ${ index } ` ,
icon ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'message-chatto' , {
id : e . id ,
} ) ;
}
} ;
} )
) ;
conversationsMenu . submenu = conversations ;
}
if ( contacts . length ) {
shouldUpdate = true ;
contacts = await Promise . all (
contacts . map ( async e => {
let icon = await getIcon ( cookies , e . id , e . avatar ) ;
return {
label : e . name ,
icon ,
click ( ) {
mainWindow . show ( ) ;
mainWindow . webContents . send ( 'show-userinfo' , {
id : e . id ,
} ) ;
}
} ;
} )
) ;
contactsMenu . submenu = contacts ;
}
if ( shouldUpdate ) {
createMenu ( ) ;
}
} ) ;
ipcMain . on ( 'message-unread' , ( event , args ) => {
var counter = args . counter ;
if ( settings . showOnTray ) {
updateTray ( counter ) ;
}
} ) ;
ipcMain . on ( 'file-paste' , ( event ) => {
var image = clipboard . readImage ( ) ;
var args = { hasImage : false } ;
if ( ! image . isEmpty ( ) ) {
let filename = tmp . tmpNameSync ( ) + '.png' ;
args = {
hasImage : true ,
filename ,
raw : image . toPNG ( ) ,
} ;
fs . writeFileSync ( filename , image . toPNG ( ) ) ;
}
event . returnValue = args ;
} ) ;
ipcMain . on ( 'file-download' , async ( event , args ) => {
var filename = args . filename ;
fs . writeFileSync ( filename , args . raw . replace ( /^data:image\/png;base64,/ , '' ) , {
encoding : 'base64' ,
// Overwrite file
flag : 'wx' ,
} ) ;
event . returnValue = filename ;
} ) ;
ipcMain . on ( 'open-file' , async ( event , filename ) => {
shell . openItem ( filename ) ;
} ) ;
ipcMain . on ( 'open-folder' , async ( event , dir ) => {
shell . openItem ( dir ) ;
} ) ;
ipcMain . on ( 'open-map' , ( event , args ) => {
event . preventDefault ( ) ;
shell . openExternal ( args . map ) ;
} ) ;
ipcMain . on ( 'open-image' , async ( event , args ) => {
var filename = ` ${ imagesCacheDir } /img_ ${ args . dataset . id } ` ;
fs . writeFileSync ( filename , args . base64 . replace ( /^data:image\/png;base64,/ , '' ) , 'base64' ) ;
shell . openItem ( filename ) ;
} ) ;
ipcMain . on ( 'is-suspend' , ( event , args ) => {
event . returnValue = isSuspend ;
} ) ;
ipcMain . once ( 'logined' , event => {
mainWindow . setResizable ( true ) ;
mainWindow . setSize ( mainWindowState . width , mainWindowState . height ) ;
mainWindowState . manage ( mainWindow ) ;
} ) ;
powerMonitor . on ( 'resume' , ( ) => {
isSuspend = false ;
mainWindow . webContents . send ( 'os-resume' ) ;
} ) ;
powerMonitor . on ( 'suspend' , ( ) => {
isSuspend = true ;
} ) ;
if ( isOsx ) {
app . setAboutPanelOptions ( {
applicationName : pkg . name ,
applicationVersion : pkg . version ,
2022-09-01 21:05:47 +08:00
copyright : 'Made with 💖 by trazyn. \n https://github.com/trazyn/weweChat \nRevise By Riceneeder \n https://gitee.com/spark-community-works-collections/wewechat-plus-plus' ,
2022-09-01 20:38:13 +08:00
credits : ` With the invaluable help of: \n web.wechat.com ` ,
version : pkg . version
} ) ;
}
[ imagesCacheDir , voicesCacheDir ] . map ( e => {
if ( ! fs . existsSync ( e ) ) {
fs . mkdirSync ( e ) ;
}
} ) ;
mainWindow . webContents . setUserAgent ( 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8' ) ;
createMenu ( ) ;
} ;
app . setName ( pkg . name ) ;
app . dock && app . dock . setIcon ( icon ) ;
app . on ( 'ready' , createMainWindow ) ;
app . on ( 'before-quit' , ( ) => {
// Fix issues #14
forceQuit = true ;
} ) ;
app . on ( 'activate' , e => {
if ( ! mainWindow . isVisible ( ) ) {
mainWindow . show ( ) ;
}
} ) ;
autoUpdater . on ( 'update-not-available' , e => {
dialog . showMessageBox ( {
type : 'info' ,
buttons : [ 'OK' ] ,
title : pkg . name ,
message : ` ${ pkg . name } is up to date :) ` ,
detail : ` ${ pkg . name } ${ pkg . version } is currently the newest version available, It looks like you're already rocking the latest version! `
} ) ;
console . log ( 'Update not available.' ) ;
} ) ;
autoUpdater . on ( 'update-available' , e => {
downloading = true ;
checkForUpdates ( ) ;
} ) ;
autoUpdater . on ( 'error' , err => {
dialog . showMessageBox ( {
type : 'error' ,
buttons : [ 'Cancel update' ] ,
title : pkg . name ,
message : ` Failed to update ${ pkg . name } :( ` ,
detail : ` An error occurred in retrieving update information, Please try again later. ` ,
} ) ;
downloading = false ;
console . error ( err ) ;
} ) ;
autoUpdater . on ( 'update-downloaded' , info => {
var { releaseNotes , releaseName } = info ;
var index = dialog . showMessageBox ( {
type : 'info' ,
buttons : [ 'Restart' , 'Later' ] ,
title : pkg . name ,
message : ` The new version has been downloaded. Please restart the application to apply the updates. ` ,
detail : ` ${ releaseName } \n \n ${ releaseNotes } `
} ) ;
downloading = false ;
if ( index === 1 ) {
return ;
}
autoUpdater . quitAndInstall ( ) ;
setTimeout ( ( ) => {
mainWindow = null ;
app . quit ( ) ;
} ) ;
} ) ;