-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.js
280 lines (261 loc) · 6.92 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
Author: OpSimple
"A useless electron client for hack.chat"
*/
/*
Import needed stuffs
*/
const fs = require('fs');
const log4js = require('log4js');
const electron = require('electron');
const prompt = require('electron-prompt');
const conextmenu = require('electron-context-menu');
const { dialog, Menu, shell, app, BrowserWindow } = electron;
/*
Initial config
*/
const ver = '0.1.5';
const iconpath = __dirname + '/icon.png';
let CONFIG = {
version : ver,
page: 'https://hack.chat/',
loglevel: 'INFO',
width: 1200,
height: 900,
extmoddirs: []
};
const appdir = require('os').homedir()+'/.hackchat-electron';
const modsdir = appdir + '/mods';
const logdir = appdir + '/logs';
const config = appdir + '/config.json';
// create app dir if doesn't exist
if (!fs.existsSync(appdir)) {
fs.mkdirSync(modsdir, { recursive: true }, (err) => {
if(err) {
throw err;
}
});
fs.mkdirSync(logdir, { recursive: true }, (err) => {
if(err) {
throw err;
}
});
createConfig();
}
if (!fs.existsSync(config)) {
createConfig();
}
// setup the logger
log4js.configure({
appenders: { app: { type: 'file', filename: logdir+'/'+Date.now()+'.log' } },
categories: { default: { appenders: ['app'], level: 'error' } }
});
const logger = log4js.getLogger('app');
logger.level = CONFIG.loglevel;
logger.info('App Started ('+ver+')!');
logger.info('appdir = ' + appdir);
// read config
logger.info('Reading config..');
readConfig();
logger.info('config = ' + JSON.stringify(CONFIG));
// Set NO for menubars
Menu.setApplicationMenu(null);
// Begin app stuffs
let window;
app.on('ready', () => {
logger.info('app ready');
// We're creating window
window = new BrowserWindow({
width: CONFIG.width,
height: CONFIG.height,
icon: iconpath,
webPreferences: {
nodeIntegration: false
}
});
// lets load home page
logger.info('loading homepage: '+ CONFIG.page);
loadHome();
// Normal right-click based context menu
conextmenu({
prepend: (defaultActions, params, browserWindow) => [
// navigate to home option
{
label: 'Home',
click: () => {
loadHome();
}
}
],
// Basic menu options
menu: actions => [
actions.separator(),
actions.cut(),
actions.copy(),
actions.paste(),
actions.copyLink(),
actions.separator()
],
// Dev and playful options
append: (defaultActions, params, browserWindow) => [
// Allow to inject a js file directly
{
label: 'Inject JavaScript',
click: () => {
// create an open dialog for user to select js files
const files = dialog.showOpenDialog(window, {
title: 'Choose js files',
filters: [
{ name: 'JavaScript files', extensions: ['js']},
{ name: 'All files', extensions: ['*'] }
],
properties: ['openFile', 'multiSelections', 'showHiddenFiles']
});
// inject the selected files one by one
if(files!=null) {
for(file of files) {
injectMod(file);
}
}
}
},
// Open dev tools to play with
{
label: 'Dev Tools',
click: () => {
window.webContents.openDevTools();
}
}
]
});
// Handle the hack.chat links and others differently
window.webContents.on('new-window', (ev, url , frname, disp, opts, addftrs, ref) => {
ev.preventDefault();
if(url.split('/')[2] === CONFIG.page.split('/')[2]) {
prompt({
title: 'Nickname',
label: 'Enter a nickname:',
type: 'input',
inputAttrs: {
type: 'text',
required: true
}
}, window).then((r) => {
if(r != null){
window.loadURL(url+'#'+r);
}
}).catch((err) => {
logger.error('Error while calling prompt: '+ err.toString());
console.log(err);
});
} else {
shell.openExternal(url);
}
});
// load modules to inject into hackchat client.js script
window.webContents.on('dom-ready', (ev) => {
// read file recursively and inject them one by one
logger.info("Loading early modules..");
const files = fs.readdirSync(modsdir, 'utf8', (err, data) => {
if(err) {
console.log(err);
logger.error('Error while trying to read the contents of modules dir :' + err.toString());
}
});
if(files!=null) {
for(file of files){
injectMod(modsdir + '/' + file);
}
}
// load mods from user given dirs
if(CONFIG.extmoddirs != null) {
for(dir in CONFIG.extmoddirs) {
const files = fs.readdirSync(dir, 'utf8', (err, files) => {
if(err) {
console.log(err);
logger.error('Error while trying to read the contents of modules dir :'+ dir + ' ' + err.toString());
}
});
if(files!=null) {
for(file of files){
injectMod(modsdir + '/' + file);
}
}
}
}
});
window.on('closed', () => {
window = null;
});
});
app.on('quit', () => {
logger.info('app quits');
});
/*
Loading home is long and required more than once
*/
function loadHome() {
if(window == null) return;
window.loadURL(CONFIG.page);
prompt({
title: 'Channel',
label: 'Enter the channel:',
type: 'input',
inputAttrs: {
type: 'text'
}
}, window).then((r) => {
if(r != null){
window.loadURL(CONFIG.page+'?'+r);
}
}).catch( (err) => {
logger.error('Error while calling prompt: '+err.toString());
console.log(err);
});
}
/*
Inject a js file
*/
function injectMod(file) {
if(window == null) return;
if(file.endsWith('.js')) {
const js = fs.readFileSync(file, 'utf8', (err,data) => {
if(err) {
logger.error('Error while trying to read file :' + file + ' ' + err.toString());
console.log(err);
return;
}
});
if(js!=null) {
logger.info('Mod Loaded: ' + file);
window.webContents.executeJavaScript(js);
}
}
}
/*
Read config
*/
function readConfig(){
const data = fs.readFileSync( config, 'utf8', (err,data) => {
if(err) {
logger.fatal('Error while trying to read config file!\n'+err.toString());
console.log(err);
return;
}
});
try {
CONFIG = JSON.parse(data);
CONFIG.version = ver;
} catch (err) {
logger.fatal('Error while trying to read config file!\n'+err.toString());
console.log(err);
return;
}
// TODO checking values
}
/*
Create config
*/
function createConfig() {
fs.writeFileSync(config, JSON.stringify(CONFIG));
}