2 // @name Thread Rebuilder
3 // @namespace http://tampermonkey.net/
5 // @description try to take over the world!
7 // @match https://boards.4chan.org/*/thread/*
8 // @match http://boards.4chan.org/*/thread/*
9 // @grant GM_xmlhttpRequest
10 // @updateURL https://github.com/ECHibiki/4chan-UserScripts/raw/master/Thread-Rebuilder.user.js
11 // @downloadURL https://github.com/ECHibiki/4chan-UserScripts/raw/master/Thread-Rebuilder.user.js
15 var threadData
= [['Comment'], ['Image URLs'], ['Image Names'] ,['Post No.']];
17 var semaphore_posts
= 1;
22 var enhance4ChanX = function(){
24 var qrWindow
= document
.getElementById("qr");
26 if(document
.getElementById("qrRebuilder") !== null) qrWindow
.removeChild(document
.getElementById("qrRebuilder"));
27 //document.getElementById("dump-button").click();
29 //console.log(document.getElementById("qr").getElementsByTagName("TEXTAREA")[0]);
30 var dList
= document
.getElementById("dump-list");
31 var filenamecontainer
= document
.getElementById("qr-filename-container");
36 var observer = new MutationObserver(function(mutate){
37 BGImg = dList.firstChild.style.backgroundImage;
38 if(BGImg !== oldBGImg && imgURL !== ""){
39 console.log("CHANGED");
40 dList.firstChild.style.backgroundImage = "url(" + imgURL + ")";
41 console.log("CHANGED");
42 oldBGImg = dList.firstChild.style.backgroundImage;
43 console.log("CHANGED");
46 else if (imgURL == ""){
50 observer.observe(dList , {attributes: true,subtree:true, childList: true, characterData: true });*/
52 if(document
.getElementById("qr-filerm") !== null)
53 document
.getElementById("qr-filerm").addEventListener("click", function(){imgURL
= "";});
56 var qrTable
= document
.createElement("TABLE");
57 qrTable
.setAttribute("id", "qrRebuilder");
58 qrTable
.setAttribute("style", "text-align:center");
59 qrWindow
.appendChild(qrTable
);
61 var instructionRow
= document
.createElement("TR");
62 var topRowNodes
= [document
.createElement("BR"),
63 document
.createTextNode("Insert the thread number of the post to rebuild"),
64 document
.createElement("BR"),
65 document
.createTextNode("Must be in the 4chan archives"),
66 document
.createElement("BR"),
70 instructionRow
.appendChild(node
);
72 qrTable
.appendChild(instructionRow
);
74 var threadRow
= document
.createElement("TR");
75 var secondRowNodes
= [
76 document
.createTextNode("Thread: "),
77 document
.createElement("INPUT"),
78 document
.createElement("INPUT"),
80 secondRowNodes
.forEach(
82 threadRow
.appendChild(node
);
84 qrTable
.appendChild(threadRow
);
86 secondRowNodes
[1].setAttribute("ID", "threadInput");
87 secondRowNodes
[1].setAttribute("style", "width:44.9%");
89 secondRowNodes
[2].setAttribute("ID", "threadButton");
90 secondRowNodes
[2].setAttribute("type", "button");
91 secondRowNodes
[2].setAttribute("value", "Set Rebuild Queue");
92 secondRowNodes
[2].addEventListener("click", function(){
93 //console.log("exce");
94 getThread(secondRowNodes
[1].value
);
96 postID
= setInterval(postRoutine
, 1000);
97 if(timeListen
=== undefined) timeListen
= setInterval(timeListenerFunction
, 1000);
106 var postRoutine = function(){
109 len
= threadData
[0].length
;
111 fillID
= setInterval(fillRoutine
, 10);
115 var stopRoutine = function(){
116 //console.log("Post Ends");
117 clearInterval(postID
);
121 var fillRoutine = function(){
122 //console.log(semaphore_posts + " " + i);
123 if(i
>= len
) {semaphore_posts
= 0 ; stopFillRoutine();}
124 else if(semaphore_posts
== 1){
126 createPost(threadData
[0][i
], threadData
[1][i
], threadData
[2][i
]);
131 var stopFillRoutine = function(){
132 //console.log("Fill Ends");
133 clearInterval(fillID
);
136 //2) GET ARCHIVED THREAD
137 var getThread = function(threadNo
){
138 threadData
= [[], [], [], []];
140 URL
= "https://a.4cdn.org/" + board
+ "/thread/" + threadNo
+ ".json";
142 var xhr
= new GM_xmlhttpRequest(({
145 responseType
: "json",
146 onload: function(data
){
147 data
= data
.response
;
149 if(data
== undefined){
150 alert("Invalid Thread ID: " + threadNo
+ ".\n4chan Archive ");
151 //draw from desu instead
154 var len
= data
["posts"].length
;
155 for(var i
= 1 ; i
< len
; i
++){
156 var comment
= data
["posts"][i
]["com"];
157 if(comment
!== undefined)
158 threadData
[0].push(comment
);
160 threadData
[0].push(-1);
162 var filename
= "" + data
["posts"][i
]["tim"] + data
["posts"][i
]["ext"];
163 if(filename
!== undefined && filename
.indexOf("undefined") == -1)
164 threadData
[1].push("https://i.4cdn.org/" + board
+ "/" + filename
);
165 else threadData
[1].push(-1);
167 threadData
[2].push(data
["posts"][i
]["filename"]);
169 threadData
[3].push(data
["posts"][i
]["no"]);
172 //console.log(threadData);
178 //3) RIP POSTS AND IMAGES
179 var createPost = function(text
, imageURL
, imageName
){
180 //console.log("url: " + imageURL);
182 var xhr
= new GM_xmlhttpRequest(({
185 responseType
: "arraybuffer",
186 onload: function(response
)
190 if(imageURL
.indexOf(".jpg") > -1){
191 blob
= new Blob([response
.response
], {type
:"image/jpeg"});
194 else if(imageURL
.indexOf(".png") > -1){
195 blob
= new Blob([response
.response
], {type
:"image/png"});
198 else if(imageURL
.indexOf(".gif") > -1){
199 blob
= new Blob([response
.response
], {type
:"image/gif"});
202 else if(imageURL
.indexOf(".webm") > -1){
203 blob
= new Blob([response
.response
], {type
:"video/webm"});
207 var name
= imageName
+ ext
;
209 //console.log("----------------");
210 //console.log("Blob: "); //console.log(blob);
211 //console.log("MIME: " + blob.type);
212 //console.log("Name: " + name);
214 //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
215 var detail
= {file
:blob
, name
:name
};
216 if (typeof cloneInto
=== 'function') {
217 detail
= cloneInto(detail
, document
.defaultView
);
219 //console.log("Detail: ");//console.log(detail);
220 document
.dispatchEvent(new CustomEvent('QRSetFile', {bubbles
:true, detail
}));
222 if(text
!== "" && text
!== undefined && text
!== -1) createPostComment(text
);
224 document
.getElementById("add-post").click();
230 createPostComment(text
);
231 document
.getElementById("add-post").click();
236 //4) CREATE POST QUEUE
237 var createPostComment = function(text
){
238 //console.log("text-Before: " + text);
240 text
= text
.replace(/<a href="\/[a-zA-Z]+\/" class="quotelink">>>>/g, ">>>");
242 var quote_regex
= /<a href="#p[0-9]+" class="quotelink">>>[0-9]+/g;
243 var find
= text
.match(quote_regex
);
245 find
.forEach(function(match
){
246 //console.log("---==");
247 var index_start
= text
.indexOf(match
);
248 var match_len
= match
.length
;
249 var index_len
= index_start
+ match_len
;
250 var first_quote
= match
.indexOf('"');
251 var second_quote
= match
.indexOf('"', first_quote
+ 1);
252 var post_no
= match
.substring(first_quote
+ 3, second_quote
);
254 match
= ">>" + post_no
;
256 text
= text
.substr(0, index_start
) + match
+ text
.substr(index_len
);
260 text
= text
.replace(/<span class="quote">>/g, ">");
261 text
= text
.replace(/<br>/g, "\n");
262 text
= text
.replace(/'/g, "'");
263 text
= text
.replace(/<\/a>/g, "");
264 text
= text
.replace(/<wbr>/g, "");
265 text
= text
.replace(/<\/span>/g, "");
267 //console.log("text-After: " + text);
268 //if(text.match(/^>>[0-9]+$/g)) document.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value = text + "\n" + Math.floor(Math.random() * 1000).toString(62)/*.replace(/[^a-z]+/g, '')*/;
270 document
.getElementById("qr").getElementsByTagName("TEXTAREA")[0].value
= text
;
274 var timeListenerFunction = function(){
276 var time
= document
.getElementById("qr-filename-container").nextSibling
.value
.replace(/[a-zA-Z]+/g, "");
279 console
.log(time
+ "A");
283 console
.log(time
+ "B");
288 window
.onload = function(){
289 //console.log(document.links);
290 var len
= document
.links
.length
;
291 for(var i
= 0 ; i
< len
; i
++){
292 document
.links
[i
].addEventListener("click", enhance4ChanX
);
295 //ENHANCE DUMP TABS (COVER, 482PX - 482PX)
296 //DUMP LIST MAX-HEIGHT TO 490
298 document
.getElementById("fourchanx-css").textContent
+= ".qr-preview { height: 482px; width: 482px; background-size: cover;}";
299 //document.getElementById("fourchanx-css").textContent += "#qr { min-width:490px;}";
300 document
.getElementById("fourchanx-css").textContent
+= "#dump-list { min-height: 400px; width: 509px;}";