1
1
// 运行在 Electron 主进程 下的插件入口
2
2
const { ipcMain, dialog, shell } = require ( "electron" ) ;
3
- const http = require ( "http" ) ;
4
- const https = require ( "https" ) ;
5
3
const path = require ( "path" ) ;
6
4
const fs = require ( "fs" ) ;
7
5
@@ -10,180 +8,24 @@ const defaultConfig = require("./defaultConfig/defaultConfig.json"); // 默认
10
8
const defalutLocalEmoticonsConfig = require ( "./defaultConfig/defalutLocalEmoticonsConfig.json" ) ; // 默认本地表情配置文件
11
9
let loadOptions = require ( "./main_modules/loadOptions" ) ;
12
10
const { loadEmoticons, onUpdateEmoticons } = require ( "./main_modules/localEmoticons" ) ;
11
+ const { LimitedMap } = require ( "./main_modules/LimitedMap" ) ;
12
+ const { MessageRecallList } = require ( "./main_modules/MessageRecallList" ) ;
13
+ const { globalBroadcast } = require ( "./main_modules/globalBroadcast" ) ;
14
+ const { processPic } = require ( "./main_modules/processPic" ) ;
15
+ const { replaceArk } = require ( "./main_modules/replaceArk" ) ;
16
+ const { debounce } = require ( "./main_modules/debounce" ) ;
17
+ const { log } = require ( "./main_modules/log" ) ;
13
18
14
19
let mainMessage , recordMessageRecallIdList , messageRecallPath , messageRecallJson ;
15
20
16
- let log = function ( ...args ) {
17
- console . log ( ...args ) ;
18
- } ;
19
-
20
- // 自定义limitMap,在达到指定数量后清空最后一条记录
21
- class LimitedMap {
22
- constructor ( limit ) {
23
- this . limit = limit ;
24
- this . map = new Map ( ) ;
25
- this . keys = [ ] ;
26
- }
27
- set ( key , value ) {
28
- // 如果当前map存储消息超过指定大小,则删除最后一条数据
29
- if ( this . map . size >= this . limit ) {
30
- const oldestKey = this . keys . shift ( ) ;
31
- this . map . delete ( oldestKey ) ;
32
- }
33
- this . map . set ( key , value ) ;
34
- this . keys . push ( key ) ;
35
- }
36
- get ( key ) {
37
- return this . map . get ( key ) ;
38
- }
39
- has ( key ) {
40
- return this . map . has ( key ) ;
41
- }
42
- delete ( key ) {
43
- const index = this . keys . indexOf ( key ) ;
44
- if ( index !== - 1 ) {
45
- this . keys . splice ( index , 1 ) ;
46
- }
47
- this . map . delete ( key ) ;
48
- }
49
- }
50
-
51
- // 撤回消息切片管理
52
- class MessageRecallList {
53
- constructor ( messageRecallJson , messageRecallPath = false , limit = 0 ) {
54
- log (
55
- `新的历史记录实例,目标文件 ${ path . basename ( messageRecallJson ) } 实例状态 ${
56
- messageRecallPath ? "读写" : "只读"
57
- } 切片大小 ${ limit } `,
58
- ) ;
59
- this . limit = limit ;
60
- this . messageRecallPath = messageRecallPath ;
61
- this . latestPath = messageRecallJson ;
62
- this . newFileEvent = [ ] ;
63
- this . map = new Map ( JSON . parse ( fs . readFileSync ( this . latestPath , { encoding : "utf-8" } ) ) ) ; // 从文件中初始化撤回信息
64
- }
65
- set ( key , value ) {
66
- if ( this . messageRecallPath ) {
67
- this . map . set ( key , value ) ;
68
- if ( this . map . size >= this . limit ) {
69
- log ( "缓存撤回消息超过阈值,开始切片" ) ;
70
- const newFileName = `${ new Date ( ) . getTime ( ) } .json` ;
71
- fs . writeFileSync ( path . join ( this . messageRecallPath , newFileName ) , JSON . stringify ( Array . from ( this . map ) ) ) ;
72
- this . newFileEvent . forEach ( ( callback ) => callback ( newFileName ) ) ;
73
- this . map = new Map ( ) ;
74
- }
75
- fs . writeFileSync ( this . latestPath , JSON . stringify ( Array . from ( this . map ) ) ) ;
76
- } else {
77
- console . error ( "该实例工作在只读模式" ) ;
78
- }
79
- }
80
- // 如果产生新的切片文件,将会调用该方法传入的回调
81
- onNewFile ( callback ) {
82
- if ( this . messageRecallPath ) {
83
- this . newFileEvent . push ( callback ) ;
84
- } else {
85
- console . error ( "该实例工作在只读模式" ) ;
86
- }
87
- }
88
- get ( key ) {
89
- return this . map . get ( key ) ;
90
- }
91
- has ( key ) {
92
- return this . map . has ( key ) ;
93
- }
94
- delete ( key ) {
95
- if ( this . messageRecallPath ) {
96
- this . map . delete ( key ) ;
97
- } else {
98
- console . error ( "该实例工作在只读模式" ) ;
99
- }
100
- }
101
- }
102
-
103
21
const listenList = [ ] ; // 所有打开过的窗口对象
104
22
const catchMsgList = new LimitedMap ( 2000 ) ; // 内存缓存消息记录-用于根据消息id获取撤回原始内容
105
23
const messageRecallFileList = [ ] ; // 所有撤回消息本地切片列表
106
24
let peer = null ; // 激活聊天界面信息
107
25
let historyMessageRecallList = new Map ( ) ; // 只读历史消息实例暂存数组
108
26
let localEmoticonsList = [ ] ; // 本地表情包数据
109
-
110
27
let options , localEmoticonsConfig ; // 配置数据
111
28
112
- // 向所有未销毁页面发送广播
113
- function globalBroadcast ( channel , data ) {
114
- listenList . forEach ( ( window ) => {
115
- if ( ! window . isDestroyed ( ) ) {
116
- window . webContents . send ( channel , data ) ;
117
- }
118
- } ) ;
119
- }
120
-
121
- // 下载被撤回的图片
122
- function processPic ( msgItem ) {
123
- msgItem ?. elements ?. forEach ( async ( el ) => {
124
- if ( el ?. picElement ) {
125
- log ( "该消息含有图片" , el ) ;
126
- const pic = el . picElement ;
127
- const picName = pic . md5HexStr . toUpperCase ( ) ;
128
- const picUrl = `https://gchat.qpic.cn/gchatpic_new/0/0-0-${ picName } /` ;
129
- if ( ! fs . existsSync ( pic . sourcePath ) ) {
130
- log ( "下载原图" , `${ picUrl } 0` ) ;
131
- const body = await downloadPic ( `${ picUrl } 0` ) ;
132
- fs . mkdirSync ( path . dirname ( pic . sourcePath ) , { recursive : true } ) ;
133
- fs . writeFileSync ( pic . sourcePath , body ) ;
134
- }
135
- // 修复本地数据中的错误
136
- if ( pic ?. thumbPath && ( pic . thumbPath instanceof Array || pic . thumbPath instanceof Object ) ) {
137
- pic . thumbPath = new Map ( [
138
- [ 0 , pic . sourcePath . replace ( "Ori" , "Thumb" ) . replace ( pic . md5HexStr , pic . md5HexStr + "_0" ) ] ,
139
- [ 198 , pic . sourcePath . replace ( "Ori" , "Thumb" ) . replace ( pic . md5HexStr , pic . md5HexStr + "_198" ) ] ,
140
- [ 720 , pic . sourcePath . replace ( "Ori" , "Thumb" ) . replace ( pic . md5HexStr , pic . md5HexStr + "_720" ) ] ,
141
- ] ) ;
142
- }
143
- if ( pic ?. thumbPath && ( pic . thumbPath instanceof Array || pic . thumbPath instanceof Map ) ) {
144
- pic . thumbPath . forEach ( async ( el , key ) => {
145
- if ( ! fs . existsSync ( el ) ) {
146
- log ( "下载缩略图" , `${ picUrl } ${ key } ` ) ;
147
- const body = await downloadPic ( `${ picUrl } ${ key } ` ) ;
148
- fs . mkdirSync ( path . dirname ( el ) , { recursive : true } ) ;
149
- fs . writeFileSync ( el , body ) ;
150
- }
151
- } ) ;
152
- }
153
- }
154
- } ) ;
155
- }
156
-
157
- // 下载方法
158
- function downloadPic ( url ) {
159
- const protocolModule = url . startsWith ( "https" ) ? https : http ;
160
- return new Promise ( ( resolve , reject ) => {
161
- function doRequest ( url ) {
162
- log ( "下载撤回消息中的图片" , url ) ;
163
- protocolModule . get ( url , ( response ) => {
164
- if ( response . statusCode >= 300 && response . statusCode < 400 && response . headers . location ) {
165
- doRequest ( response . headers . location ) ;
166
- } else {
167
- const chunks = [ ] ;
168
- response . on ( "data" , ( chunk ) => {
169
- chunks . push ( chunk ) ;
170
- } ) ;
171
- response . on ( "end" , ( ) => {
172
- const responseData = Buffer . concat ( chunks ) ;
173
- resolve ( responseData ) ; // 解析 Promise 并传递数据
174
- log ( "下载图片完成" ) ;
175
- } ) ;
176
- response . on ( "error" , ( err ) => {
177
- log ( "下载图片失败" , err ) ;
178
- reject ( err ) ; // 解析 Promise 并传递错误
179
- } ) ;
180
- }
181
- } ) ;
182
- }
183
- doRequest ( url ) ;
184
- } ) ;
185
- }
186
-
187
29
// 加载插件时触发
188
30
function onLoad ( plugin ) {
189
31
const pluginDataPath = plugin . path . data ;
@@ -250,7 +92,7 @@ function onLoad(plugin) {
250
92
debounce ( ( ) => {
251
93
const cssText = sass . compile ( styleSassPath ) . css ;
252
94
fs . writeFileSync ( stylePath , cssText ) ;
253
- globalBroadcast ( "LiteLoader.lite_tools.updateStyle" , cssText ) ;
95
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateStyle" , cssText ) ;
254
96
} , 100 ) ,
255
97
) ;
256
98
// 监听并编译global.scss
@@ -260,7 +102,7 @@ function onLoad(plugin) {
260
102
debounce ( ( ) => {
261
103
const cssText = sass . compile ( globalScssPath ) . css ;
262
104
fs . writeFileSync ( globalPath , cssText ) ;
263
- globalBroadcast ( "LiteLoader.lite_tools.updateGlobalStyle" , cssText ) ;
105
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateGlobalStyle" , cssText ) ;
264
106
} , 100 ) ,
265
107
) ;
266
108
// 监听并编译view.scss
@@ -270,7 +112,7 @@ function onLoad(plugin) {
270
112
debounce ( ( ) => {
271
113
const cssText = sass . compile ( settingScssPath ) . css ;
272
114
fs . writeFileSync ( settingPath , cssText ) ;
273
- globalBroadcast ( "LiteLoader.lite_tools.updateSettingStyle" ) ;
115
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateSettingStyle" ) ;
274
116
} , 100 ) ,
275
117
) ;
276
118
} catch {
@@ -290,7 +132,13 @@ function onLoad(plugin) {
290
132
// 监听本地表情包文件夹内的更新
291
133
onUpdateEmoticons ( ( emoticonsList ) => {
292
134
console . log ( "本地表情包更新" , emoticonsList . length ) ;
293
- globalBroadcast ( "LiteLoader.lite_tools.updateEmoticons" , emoticonsList ) ;
135
+ if ( options . localEmoticons . commonlyEmoticons ) {
136
+ emoticonsList . unshift ( {
137
+ name : "常用表情" ,
138
+ list : localEmoticonsConfig . commonlyEmoticons ,
139
+ } ) ;
140
+ }
141
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateEmoticons" , emoticonsList ) ;
294
142
localEmoticonsList = emoticonsList ;
295
143
} ) ;
296
144
@@ -348,7 +196,7 @@ function onLoad(plugin) {
348
196
concat = options . textAreaFuncList . concat ( list ) ;
349
197
options . textAreaFuncList = concat . filter ( ( item ) => ! res . has ( item [ "name" ] ) && res . set ( item [ "name" ] , 1 ) ) ;
350
198
fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
351
- globalBroadcast ( "LiteLoader.lite_tools.updateOptions" , options ) ;
199
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateOptions" , options ) ;
352
200
} ) ;
353
201
354
202
// 更新聊天框上方功能列表
@@ -357,21 +205,22 @@ function onLoad(plugin) {
357
205
concat = options . chatAreaFuncList . concat ( list ) ;
358
206
options . chatAreaFuncList = concat . filter ( ( item ) => ! res . has ( item [ "name" ] ) && res . set ( item [ "name" ] , 1 ) ) ;
359
207
fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
360
- globalBroadcast ( "LiteLoader.lite_tools.updateOptions" , options ) ;
208
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateOptions" , options ) ;
361
209
} ) ;
362
210
363
211
// 修改配置信息
364
212
ipcMain . on ( "LiteLoader.lite_tools.setOptions" , ( event , opt ) => {
365
213
log ( "%c更新配置信息" , "background:#1a5d1a;color:#fff;" , opt ) ;
366
- options = opt ;
367
- fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
368
214
// 判断是否启用了本地表情包功能
369
- if ( options . localEmoticons . enabled ) {
370
- if ( options . localEmoticons . localPath ) {
371
- loadEmoticons ( options . localEmoticons . localPath ) ;
215
+ if ( opt . localEmoticons . enabled ) {
216
+ if ( opt . localEmoticons . localPath && options . localEmoticons . localPath !== opt . localEmoticons . localPath ) {
217
+ resetCommonlyEmoticons ( ) ; // 重置常用表情
218
+ loadEmoticons ( opt . localEmoticons . localPath ) ;
372
219
}
373
220
}
374
- globalBroadcast ( "LiteLoader.lite_tools.updateOptions" , options ) ;
221
+ options = opt ;
222
+ fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
223
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateOptions" , options ) ;
375
224
} ) ;
376
225
377
226
// 获取配置信息
@@ -436,7 +285,7 @@ function onLoad(plugin) {
436
285
if ( ! result . canceled ) {
437
286
options . background . url = path . join ( result . filePaths [ 0 ] ) . replace ( / \\ / g, "/" ) ;
438
287
fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
439
- globalBroadcast ( "LiteLoader.lite_tools.updateOptions" , options ) ;
288
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateOptions" , options ) ;
440
289
}
441
290
} )
442
291
. catch ( ( err ) => {
@@ -455,15 +304,17 @@ function onLoad(plugin) {
455
304
. then ( ( result ) => {
456
305
console . log ( "选择了文件夹" , result ) ;
457
306
if ( ! result . canceled ) {
458
- options . localEmoticons . localPath = path . join ( result . filePaths [ 0 ] ) . replace ( / \\ / g, "/" ) ;
459
- fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
307
+ const newPath = path . join ( result . filePaths [ 0 ] ) . replace ( / \\ / g, "/" ) ;
460
308
// 判断是否启用了本地表情包功能
461
309
if ( options . localEmoticons . enabled ) {
462
- if ( options . localEmoticons . localPath ) {
463
- loadEmoticons ( options . localEmoticons . localPath ) ;
310
+ if ( newPath && options . localEmoticons . localPath !== newPath ) {
311
+ resetCommonlyEmoticons ( ) ;
312
+ loadEmoticons ( newPath ) ;
464
313
}
465
314
}
466
- globalBroadcast ( "LiteLoader.lite_tools.updateOptions" , options ) ;
315
+ options . localEmoticons . localPath = newPath ;
316
+ fs . writeFileSync ( settingsPath , JSON . stringify ( options , null , 4 ) ) ;
317
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.updateOptions" , options ) ;
467
318
}
468
319
} )
469
320
. catch ( ( err ) => {
@@ -761,7 +612,7 @@ function onBrowserWindowCreated(window, plugin) {
761
612
origMsgSenderNick : msgItem . elements [ 0 ] . grayTipElement . revokeElement . origMsgSenderNick , // 发送消息角色
762
613
recallTime : msgItem . recallTime , // 撤回时间
763
614
} ;
764
- globalBroadcast ( "LiteLoader.lite_tools.onMessageRecall" , {
615
+ globalBroadcast ( listenList , "LiteLoader.lite_tools.onMessageRecall" , {
765
616
msgId : findInCatch . msgId ,
766
617
recallData,
767
618
} ) ;
@@ -793,57 +644,10 @@ function onBrowserWindowCreated(window, plugin) {
793
644
window . webContents . send = patched_send ;
794
645
}
795
646
796
- // 卡片替换函数
797
- function replaceArk ( json , msg_seq ) {
798
- log ( "%c替换小程序卡片" , "background:#fba1b7;color:#fff;" , json ) ;
799
- return JSON . stringify ( {
800
- app : "com.tencent.structmsg" ,
801
- config : json . config ,
802
- desc : "新闻" ,
803
- extra : { app_type : 1 , appid : json . meta . detail_1 . appid , msg_seq, uin : json . meta . detail_1 . host . uin } ,
804
- meta : {
805
- news : {
806
- action : "" ,
807
- android_pkg_name : "" ,
808
- app_type : 1 ,
809
- appid : json . meta . detail_1 . appid ,
810
- ctime : json . config . ctime ,
811
- desc : json . meta . detail_1 . desc ,
812
- jumpUrl : json . meta . detail_1 . qqdocurl . replace ( / \\ / g, "" ) ,
813
- preview : json . meta . detail_1 . preview ,
814
- source_icon : json . meta . detail_1 . icon ,
815
- source_url : "" ,
816
- tag : getArkData ( json ) ,
817
- title : getArkData ( json ) ,
818
- uin : json . meta . detail_1 . host . uin ,
819
- } ,
820
- } ,
821
- prompt : `[分享]${ getArkData ( json ) } ` ,
822
- ver : "0.0.0.1" ,
823
- view : "news" ,
824
- } ) ;
825
- }
826
-
827
- // appid对应小程序名称
828
- const appidName = new Map ( [
829
- [ "1109224783" , "微博" ] ,
830
- [ "1109937557" , "哔哩哔哩" ] ,
831
- ] ) ;
832
-
833
- // 获取ark卡片对应内容
834
- function getArkData ( json ) {
835
- return json . meta . detail_1 . title || appidName . get ( json . meta . detail_1 . appid ) || json . meta . detail_1 . desc ;
836
- }
837
-
838
- // 防抖函数
839
- function debounce ( fn , time ) {
840
- let timer = null ;
841
- return function ( ...args ) {
842
- timer && clearTimeout ( timer ) ;
843
- timer = setTimeout ( ( ) => {
844
- fn . apply ( this , args ) ;
845
- } , time ) ;
846
- } ;
647
+ // 重置常用表情列表
648
+ function resetCommonlyEmoticons ( ) {
649
+ localEmoticonsConfig . commonlyEmoticons = [ ] ;
650
+ fs . writeFileSync ( localEmoticonsPath , JSON . stringify ( localEmoticonsConfig , null , 4 ) ) ;
847
651
}
848
652
849
653
// 这两个函数都是可选的
0 commit comments