@@ -29,7 +29,12 @@ function createPostTreeWalker(post) {
29
29
// Validating
30
30
if ( node . nodeName === 'IMG' ) {
31
31
// Constructing URL
32
- const url = new URL ( node . src ) ;
32
+ let url ;
33
+ try {
34
+ url = new URL ( node . src ) ;
35
+ } catch {
36
+ return NodeFilter . FILTER_SKIP ;
37
+ }
33
38
34
39
// Checking to see if it's a valid post
35
40
if ( mediaLinks . includes ( url . hostname ) && url . searchParams . has ( 'blur' ) ) {
@@ -49,49 +54,51 @@ function createPostTreeWalker(post) {
49
54
* @param {Node } mediaNode The media node, often an image, to find the thread to
50
55
* @returns {string } The source.
51
56
*/
52
- function findExternalNode ( mediaNode ) {
53
- let depth = 0 ;
54
- let par = mediaNode ;
55
- while ( par && par . classList ) {
56
- if ( par . classList . contains ( 'scrollerItem' ) || par . nodeName == 'A' || depth >= 15 ) break ;
57
- par = par . parentNode ;
58
- depth ++ ;
59
- }
57
+ async function findExternalNode ( mediaNode ) {
58
+ return new Promise ( ( resolve , reject ) => {
59
+ let depth = 0 ;
60
+ let par = mediaNode ;
61
+ while ( par && par . classList ) {
62
+ if ( par . classList . contains ( 'scrollerItem' ) || par . nodeName == 'A' || depth >= 15 ) break ;
63
+ par = par . parentNode ;
64
+ depth ++ ;
65
+ }
60
66
61
- // Handling the gathered node
62
- if ( ! par ) return null ;
63
- if ( par . nodeName == 'A' ) {
64
- return par ;
65
- } else {
66
- // i forgot what this entire section is even for..
67
- // const treeWalker = document.createTreeWalker(par, NodeFilter.SHOW_ELEMENT, (node) => {
68
- // // Validating
69
- // if (node.nodeName == 'A') {
70
- // if (invalidSourceLinks.filter((link) => node.href.match(link) != null).length <= 0)
71
- // return NodeFilter.FILTER_ACCEPT;
72
- // }
73
-
74
- // return NodeFilter.FILTER_SKIP;
75
- // });
76
-
77
-
78
- // while (treeWalker.nextNode()) {
79
- // // Prevent duplicate
80
- // let flag = true;
81
- // const postWalker = createPostTreeWalker(treeWalker.currentNode);
82
- // while (postWalker.nextNode()) {
83
- // console.log(`node ${postWalker.currentNode} .. ${postWalker.currentNode.src}`)
84
- // if (postWalker.currentNode.src == mediaNode.src) {
85
- // flag = false;
86
- // console.log('found duplicate');
87
- // break;
88
- // }
89
- // }
90
-
91
- // if (!flag) continue;
92
- // return treeWalker.currentNode;
93
- // }
94
- }
67
+ // Handling the gathered node
68
+ if ( ! par ) return null ;
69
+ if ( par . nodeName == 'A' ) {
70
+ resolve ( par ) ;
71
+ } else {
72
+ // i forgot what this entire section is even for..
73
+ // const treeWalker = document.createTreeWalker(par, NodeFilter.SHOW_ELEMENT, (node) => {
74
+ // // Validating
75
+ // if (node.nodeName == 'A') {
76
+ // if (invalidSourceLinks.filter((link) => node.href.match(link) != null).length <= 0)
77
+ // return NodeFilter.FILTER_ACCEPT;
78
+ // }
79
+
80
+ // return NodeFilter.FILTER_SKIP;
81
+ // });
82
+
83
+
84
+ // while (treeWalker.nextNode()) {
85
+ // // Prevent duplicate
86
+ // let flag = true;
87
+ // const postWalker = createPostTreeWalker(treeWalker.currentNode);
88
+ // while (postWalker.nextNode()) {
89
+ // console.log(`node ${postWalker.currentNode} .. ${postWalker.currentNode.src}`)
90
+ // if (postWalker.currentNode.src == mediaNode.src) {
91
+ // flag = false;
92
+ // console.log('found duplicate');
93
+ // break;
94
+ // }
95
+ // }
96
+
97
+ // if (!flag) continue;
98
+ // return treeWalker.currentNode;
99
+ // }
100
+ }
101
+ } ) ;
95
102
}
96
103
97
104
/**
@@ -138,19 +145,20 @@ function removeMediaSpoiler(mediaNode, source) {
138
145
}
139
146
140
147
// Fix the post
141
- let linkNode = findExternalNode ( mediaNode ) ;
142
- for ( let child of linkNode . children ) {
143
- if ( child !== mediaNode && child . nodeName == "DIV" ) {
144
- let children = Array . from ( child . children ) ;
145
- children = children . filter ( ( x ) => {
146
- return x . nodeName === "BUTTON" && x . innerHTML . includes ( 'spoiler' ) ;
147
- } ) ;
148
-
149
- if ( children [ 0 ] ) {
150
- children [ 0 ] . style . display = "none" ;
148
+ findExternalNode ( mediaNode ) . then ( ( linkNode ) => {
149
+ for ( let child of linkNode . children ) {
150
+ if ( child !== mediaNode && child . nodeName == "DIV" ) {
151
+ let children = Array . from ( child . children ) ;
152
+ children = children . filter ( ( x ) => {
153
+ return x . nodeName === "BUTTON" && x . innerHTML . includes ( 'spoiler' ) ;
154
+ } ) ;
155
+
156
+ if ( children [ 0 ] ) {
157
+ children [ 0 ] . style . display = "none" ;
158
+ }
151
159
}
152
160
}
153
- }
161
+ } ) ;
154
162
}
155
163
156
164
/**
@@ -159,7 +167,7 @@ function removeMediaSpoiler(mediaNode, source) {
159
167
* @param {string } externalSrc The link of the external media source to scan.
160
168
* @returns {string } The unspoilered source link to the media.
161
169
*/
162
- function grabSourceFromImage ( blurredSrc , externalSrc ) {
170
+ async function grabSourceFromImage ( blurredSrc , externalSrc ) {
163
171
return new Promise ( ( resolve , reject ) => {
164
172
// Checking to see if the link isn't already unblurred
165
173
const splitURL = externalSrc . split ( '?' ) [ 1 ] ;
@@ -217,74 +225,88 @@ function grabSourceFromImage(blurredSrc, externalSrc) {
217
225
/**
218
226
* Attempts to get all images from the reddit post.
219
227
* @param {Node } post the post to search for images in.
220
- * @param {(mediaNode: Node, source: string) } callback the function to call each time an image is found.
221
228
*/
222
- function getImagesFromPost ( post , callback ) {
223
- // Creating tree walker from post
224
- const treeWalker = createPostTreeWalker ( post ) ;
225
- let currentNode = treeWalker . currentNode ;
226
-
227
- while ( currentNode ) {
228
- let source = findExternalNode ( treeWalker . currentNode ) ;
229
- if ( source ) {
230
- callback ( treeWalker . currentNode , source . href )
229
+ async function getImagesFromPost ( post ) {
230
+ return new Promise ( ( resolve , reject ) => {
231
+ // Creating tree walker from post
232
+ const treeWalker = createPostTreeWalker ( post ) ;
233
+ let currentNode = treeWalker . currentNode ;
234
+ let promises = [ ] ;
235
+
236
+ while ( currentNode ) {
237
+ promises . push ( findExternalNode ( treeWalker . currentNode ) ) ;
238
+ currentNode = treeWalker . nextNode ( ) ;
231
239
}
232
240
233
- currentNode = treeWalker . nextNode ( ) ;
234
- }
241
+ // getting promises
242
+ Promise . race ( promises ) . then ( ( source ) => {
243
+ resolve ( { mediaNode : treeWalker . currentNode , source : source . href } ) ;
244
+ } )
245
+ } )
235
246
}
236
247
237
248
/**
238
249
* Main function that will remove spoilers from posts, and check against the whitelist or blacklist
239
250
* @param {Node } post The post to remove spoilered media from.
240
251
*/
241
- function removePostSpoiler ( post , pageType ) {
252
+ async function removePostSpoiler ( post , pageType ) {
242
253
// Stopping unnecessary posts from continuing
243
254
//if (post.nodeName !== "IMG" && !post.classList.contains('Post')) return;
244
255
245
256
// Managing different types
246
257
let postType ;
247
258
if ( pageType == 'thread' ) {
248
- getImagesFromPost ( post , removeMediaSpoiler ) ;
259
+ getImagesFromPost ( post ) . then ( ( { mediaNode, source } ) => {
260
+ removeMediaSpoiler ( mediaNode , source ) ;
261
+ } ) ;
262
+
249
263
post . click ( ) ;
250
264
} else {
251
- getImagesFromPost ( post , ( mediaNode , source ) => {
265
+ getImagesFromPost ( post ) . then ( ( { mediaNode, source } ) => {
266
+ if ( ! mediaNode || ! source ) return ;
252
267
grabSourceFromImage ( mediaNode . src , source ) . then ( ( content ) => {
253
268
removeMediaSpoiler ( mediaNode , content ) ;
254
269
} )
255
- } ) ;
270
+ } )
256
271
}
257
272
}
258
273
259
274
/* ---------------------- */
260
275
261
- // Grabbing the rootNode depending on the post type
262
- let rootNode , postType ;
263
- if ( window . location . href . split ( '/' ) [ 5 ] !== 'comments' ) {
264
- // Dynamically grabbing for homepage type
265
- let depth = 0 ;
266
- rootNode = document . getElementsByClassName ( 'scrollerItem Post' ) [ 0 ] ;
267
- while ( rootNode . parentNode !== null && depth < 10 ) {
268
- if ( rootNode . childNodes . length > 5 ) break ;
269
-
270
- rootNode = rootNode . parentNode ;
271
- depth ++ ;
276
+ ( ( ) => {
277
+ // Grabbing the rootNode depending on the post type
278
+ let rootNode , postType ;
279
+ if ( window . location . href . split ( '/' ) [ 5 ] !== 'comments' ) {
280
+ // Dynamically grabbing for homepage type
281
+ let depth = 0 ;
282
+ rootNode = document . getElementsByClassName ( 'scrollerItem Post' ) [ 0 ] ;
283
+ while ( rootNode && depth < 10 ) {
284
+ rootNode = rootNode . parentNode ;
285
+ if ( rootNode . childNodes . length > 5 ) break ;
286
+
287
+ depth ++ ;
288
+ }
289
+ } else {
290
+ rootNode = document . getElementsByClassName ( 'Post' ) [ 0 ] ;
291
+ postType = 'thread' ;
272
292
}
273
293
274
- // Call initial function on all child nodes
275
- rootNode . childNodes . forEach ( ( x ) => { removePostSpoiler ( x , postType ) } ) ;
276
- } else {
277
- rootNode = document . getElementsByClassName ( 'Post' ) [ 0 ] ;
278
- postType = 'thread' ;
294
+ // Handling rootnode missing
295
+ if ( ! rootNode ) return ;
296
+ console . log ( "Spectacles loaded successfully!" )
279
297
280
- // Remove spoiler on 'root' because this should be the only post
281
- removePostSpoiler ( rootNode )
282
- }
298
+ // Handling spoiler removal on load
299
+ if ( postType === 'thread' ) {
300
+ removePostSpoiler ( rootNode )
301
+ } else {
302
+ rootNode . childNodes . forEach ( ( x ) => { removePostSpoiler ( x , postType ) } ) ;
303
+ }
283
304
284
- // Setting up a listener to detect when new posts are added
285
- VM . observe ( rootNode , ( mutList ) => {
286
- mutList . filter ( ( mut ) => mut . type === 'childList' ) . map ( ( mut ) => mut . addedNodes [ 0 ] ) . forEach ( ( x ) => {
287
- if ( ! x ) return false ;
288
- removePostSpoiler ( x , postType )
289
- } ) ;
290
- } , { childList : true } ) ;
305
+ // Setting up a listener to detect when new posts are added
306
+ VM . observe ( rootNode , ( mutList ) => {
307
+ mutList . filter ( ( mut ) => mut . type === 'childList' ) . map ( ( mut ) => mut . addedNodes [ 0 ] ) . forEach ( ( x ) => {
308
+ if ( ! x ) return false ;
309
+ removePostSpoiler ( x , postType )
310
+ } ) ;
311
+ } , { childList : true } ) ;
312
+ } ) ( ) ;
0 commit comments