1
1
// ==UserScript==
2
2
// @name Greasy Fork++
3
3
// @namespace https://github.com/iFelix18
4
- // @version 3.2.62
4
+ // @version 3.3.0
5
5
// @author CY Fung <https://greasyfork.org/users/371179> & Davide <[email protected] >
6
6
// @icon https://www.google.com/s2/favicons?domain=https://greasyfork.org
7
7
// @description Adds various features and improves the Greasy Fork experience
@@ -190,6 +190,14 @@ const mWindow = isInIframe || (() => {
190
190
default : '' ,
191
191
save : false
192
192
} ,
193
+ hideRecentUsersWithin : {
194
+ label : 'Hide Recent Users:<br><span>Hide new regeistered users within the last N hours - to avoid seeing comments from spam accounts</span>' ,
195
+ labelPos : 'left' ,
196
+ type : 'text' ,
197
+ title : 'Number only. 0 means disabled. maximum is 168. (Suggested value: 48)' ,
198
+ default : '0' ,
199
+ size : 150
200
+ } ,
193
201
logging : {
194
202
label : 'Logging' ,
195
203
section : [ 'Developer options' ] ,
@@ -374,14 +382,16 @@ const mWindow = isInIframe || (() => {
374
382
}
375
383
#greasyfork-plus_customBlacklist_var[class],
376
384
#greasyfork-plus_hiddenList_var[class],
377
- #greasyfork-plus_milestoneNotification_var[class]{
385
+ #greasyfork-plus_milestoneNotification_var[class],
386
+ #greasyfork-plus_hideRecentUsersWithin_var[class]{
378
387
flex-direction:column;
379
388
margin-left:21px;
380
389
}
381
390
382
391
#greasyfork-plus_customBlacklist_var[class]::before,
383
392
#greasyfork-plus_hiddenList_var[class]::before,
384
- #greasyfork-plus_milestoneNotification_var[class]::before{
393
+ #greasyfork-plus_milestoneNotification_var[class]::before,
394
+ #greasyfork-plus_hideRecentUsersWithin_var[class]::before{
385
395
/* content: "◉"; */
386
396
content: "◎";
387
397
position: absolute;
@@ -636,6 +646,10 @@ const mWindow = isInIframe || (() => {
636
646
min-height: unset;
637
647
}
638
648
649
+ .discussion-item-by-recent-user{
650
+ opacity: 0.2;
651
+ }
652
+
639
653
640
654
`
641
655
@@ -1131,6 +1145,184 @@ inIframeFn() || (async () => {
1131
1145
await gmc . initialized . then ( ) ;
1132
1146
const customBlacklistRE = createRE ( ( gmc . get ( 'customBlacklist' ) || '' ) . replace ( / \s / g, '' ) . split ( ',' ) . join ( '|' ) , 'giu' ) ;
1133
1147
1148
+ const valHideRecentUsersWithin_ = Math . floor ( + gmc . get ( 'hideRecentUsersWithin' ) ) ;
1149
+ const valHideRecentUsersWithin = valHideRecentUsersWithin_ > 168 ? 168 : valHideRecentUsersWithin_ > 0 ? valHideRecentUsersWithin_ : 0 ;
1150
+
1151
+ /**
1152
+ * Inserts an element into a sorted array using the given comparator function.
1153
+ *
1154
+ * @param {Array } arr - The sorted array.
1155
+ * @param {* } element - The new element to insert.
1156
+ * @param {Function } comparator - A function that takes two arguments (a, b)
1157
+ * and returns a negative number if a < b,
1158
+ * zero if a === b, or a positive number if a > b.
1159
+ */
1160
+ function insertSorted ( arr , element , comparator ) {
1161
+ let left = 0 ;
1162
+ let right = arr . length ;
1163
+
1164
+ // Use binary search to find the correct index for insertion.
1165
+ while ( left < right ) {
1166
+ const mid = Math . floor ( ( left + right ) / 2 ) ;
1167
+ if ( comparator ( element , arr [ mid ] ) < 0 ) {
1168
+ right = mid ;
1169
+ } else {
1170
+ left = mid + 1 ;
1171
+ }
1172
+ }
1173
+
1174
+ // Insert the element at the found index.
1175
+ arr . splice ( left , 0 , element ) ;
1176
+ return arr ;
1177
+ }
1178
+
1179
+ function findIndexSorted ( arr , element , comparator ) {
1180
+ let left = 0 ;
1181
+ let right = arr . length ;
1182
+
1183
+ // Use binary search to find the correct index for insertion.
1184
+ while ( left < right ) {
1185
+ const mid = Math . floor ( ( left + right ) / 2 ) ;
1186
+ if ( comparator ( element , arr [ mid ] ) < 0 ) {
1187
+ right = mid ;
1188
+ } else {
1189
+ left = mid + 1 ;
1190
+ }
1191
+ }
1192
+
1193
+ return left ; // arr_j > target [ arr_(j-1) <= target ]
1194
+
1195
+ }
1196
+
1197
+ let targetHiddenRecentDateTime = 0 ;
1198
+ let userCreations = [ ] ;
1199
+ let recentUserMP = Promise . resolve ( 0 ) ;
1200
+ const fetchUserCreations = ( ) => {
1201
+ if ( sessionStorage . __TMP_userCreations682__ ) {
1202
+ try {
1203
+ return JSON . parse ( sessionStorage . __TMP_userCreations682__ ) ;
1204
+ // console.log(388, userCreations);
1205
+ } catch ( e ) {
1206
+ console . warn ( e ) ;
1207
+ }
1208
+ }
1209
+ return [ ] ;
1210
+ }
1211
+ userCreations = fetchUserCreations ( ) ;
1212
+ const cleanupUserCreations = ( ) => {
1213
+
1214
+ // in case the record in sessionStorage is modified by other instances as well.
1215
+ {
1216
+ let storedUserCreations = fetchUserCreations ( ) ;
1217
+ let encodedArrS = storedUserCreations . map ( e => e . join ( ',' ) ) ;
1218
+ let encodedArrC = userCreations . map ( e => e . join ( ',' ) ) ;
1219
+ let encodedSetC = new Set ( encodedArrC ) ;
1220
+ let encodedArrSFiltered = encodedArrS . filter ( e => ! encodedSetC . has ( e ) ) ;
1221
+ let elementsMissing = encodedArrSFiltered . map ( e => e . split ( ',' ) . map ( d => + d ) ) ;
1222
+ for ( const element of elementsMissing ) {
1223
+ insertSorted ( userCreations , element , ( a , b ) => a [ 1 ] - b [ 1 ] ) ;
1224
+ }
1225
+ }
1226
+
1227
+ // since targetHiddenRecentDateTime is expected monotonic increasing, small values are useless in checking.
1228
+ let deleteCount = 0 ;
1229
+ for ( let i = 0 ; i < userCreations . length - 1 ; i ++ ) {
1230
+ if ( userCreations [ i ] [ 1 ] < targetHiddenRecentDateTime && userCreations [ i + 1 ] [ 1 ] < targetHiddenRecentDateTime ) {
1231
+ deleteCount ++ ;
1232
+ } else {
1233
+ break ;
1234
+ }
1235
+ }
1236
+ if ( deleteCount > 0 ) {
1237
+ deleteCount === 1 ? userCreations . shift ( ) : userCreations . splice ( 0 , deleteCount ) ;
1238
+ }
1239
+
1240
+ // trim the cache array to "8 + HALF" element size
1241
+ while ( userCreations . length > 32 ) {
1242
+ // remove idx 8, 10, 12, ... 32, etc.
1243
+ // 33 -> 20; 34 -> 21; 35 -> 21 , 36 -> 22, ...
1244
+ // len2 = Math.floor(len1 / 2) + 4
1245
+ // 58 -> 33 -> 20
1246
+ userCreations = userCreations . filter ( ( e , idx ) => {
1247
+ if ( idx < 8 ) return true ;
1248
+ return ( idx % 2 ) === 1 ;
1249
+ } ) ;
1250
+ }
1251
+
1252
+ sessionStorage . __TMP_userCreations682__ = JSON . stringify ( userCreations ) ;
1253
+ // console.log(1238, userCreations);
1254
+
1255
+ } ;
1256
+ const mightHideDiscussionByRecentlyNewUser = async ( userId ) => {
1257
+
1258
+ let result = null ;
1259
+
1260
+ const tryBeforeNetworkRequest = ( ) => {
1261
+
1262
+ let idxJ = findIndexSorted ( userCreations , [ null , targetHiddenRecentDateTime ] , ( a , b ) => a [ 1 ] - b [ 1 ] ) ;
1263
+
1264
+ // findIndexSorted's result is arr_j[1] > targetHiddenRecentDateTime; reduce index for equality case
1265
+ while ( idxJ > 0 && userCreations [ idxJ - 1 ] [ 1 ] >= targetHiddenRecentDateTime ) {
1266
+ idxJ -- ;
1267
+ }
1268
+
1269
+ let newFrom = 0 , oldFrom = 0 ;
1270
+
1271
+ if ( idxJ >= 0 && idxJ < userCreations . length && userCreations [ idxJ ] [ 1 ] >= targetHiddenRecentDateTime ) {
1272
+ newFrom = userCreations [ idxJ ] [ 0 ] ;
1273
+ }
1274
+
1275
+ if ( newFrom > 0 && userId >= newFrom ) {
1276
+ // console.log('newForm -> isRecent', userId, userCreations[idxJ][0], userCreations[idxJ][1], 'target', targetHiddenRecentDateTime)
1277
+ return ( result = true ) ;
1278
+ }
1279
+
1280
+ if ( idxJ > 0 && idxJ - 1 < userCreations . length && userCreations [ idxJ - 1 ] [ 1 ] < targetHiddenRecentDateTime ) {
1281
+ oldFrom = userCreations [ idxJ - 1 ] [ 0 ] ;
1282
+ }
1283
+
1284
+ if ( oldFrom > 0 && userId <= oldFrom ) {
1285
+ // console.log('oldFrom -> notRecent', userId, userCreations[idxJ-1][0], userCreations[idxJ-1][1], 'target', targetHiddenRecentDateTime)
1286
+ return ( result = false ) ;
1287
+ }
1288
+
1289
+ return { newFrom, oldFrom } ;
1290
+
1291
+ }
1292
+
1293
+ tryBeforeNetworkRequest ( ) ;
1294
+ if ( result !== null ) return result ;
1295
+
1296
+ recentUserMP = recentUserMP . then ( async ( ) => {
1297
+
1298
+ try {
1299
+
1300
+ const { newFrom, oldFrom } = tryBeforeNetworkRequest ( ) ;
1301
+ if ( result !== null ) return result ;
1302
+
1303
+ // console.log(505, newFrom, oldFrom, userId);
1304
+
1305
+ const userData = await getUserData ( userId , false ) ;
1306
+ if ( userData . id !== userId ) return ( result = false ) ;
1307
+ const insertData = [ userId , + ( new Date ( userData . created_at ) ) ] ;
1308
+ insertSorted ( userCreations , insertData , ( a , b ) => a [ 1 ] - b [ 1 ] ) ;
1309
+
1310
+ // console.log('regDate', insertData);
1311
+
1312
+ result = insertData [ 1 ] >= targetHiddenRecentDateTime ;
1313
+ cleanupUserCreations ( ) ;
1314
+
1315
+ } catch ( e ) {
1316
+ console . warn ( e ) ;
1317
+ }
1318
+
1319
+ } ) ;
1320
+
1321
+ await recentUserMP . then ( ) ;
1322
+ return result ;
1323
+
1324
+ }
1325
+
1134
1326
if ( typeof GM . registerMenuCommand === 'function' ) {
1135
1327
GM . registerMenuCommand ( 'Configure' , ( ) => gmc . open ( ) ) ;
1136
1328
GM . registerMenuCommand ( 'Reset Everything' , ( ) => {
@@ -2217,6 +2409,7 @@ inIframeFn() || (async () => {
2217
2409
}
2218
2410
2219
2411
const foundDiscussionList = ( discussionsList ) => {
2412
+ targetHiddenRecentDateTime = Date . now ( ) - valHideRecentUsersWithin * 3600000 ;
2220
2413
2221
2414
let rid = 0 ;
2222
2415
let g = ( ) => {
@@ -2242,6 +2435,17 @@ inIframeFn() || (async () => {
2242
2435
// if (gmc.get('showInstallButton')) {
2243
2436
// showInstallButton(scriptID, element)
2244
2437
// }
2438
+ let t ;
2439
+ if ( t = element . querySelector ( 'a.user-link[href*="/users/"]' ) ) {
2440
+ const m = / \/ u s e r s \/ ( \d + ) / . exec ( `${ t . getAttribute ( 'href' ) } ` ) ;
2441
+ if ( m ) {
2442
+ const userId = + m [ 1 ] ;
2443
+ mightHideDiscussionByRecentlyNewUser ( userId ) . then ( ( isNewUser ) => {
2444
+ element . classList . toggle ( 'discussion-item-by-recent-user' , isNewUser ) ;
2445
+ } ) ;
2446
+ }
2447
+ }
2448
+
2245
2449
}
2246
2450
2247
2451
}
0 commit comments