Feature Toggles[forgot version update]
[4Free-FSE.git] / src / thread-rebuilder.ts
blob666823fe16996e6066593d57728a20b0adf78da7
1 declare var cloneInto: any;
2 declare var GM_xmlhttpRequest: any;
4 class ThreadRebuilder extends FeatureInterface{
6         board = "qa";
7         thread_data = [['Comment'], ['Image URLs'], ['Image Names'] ,['Post No.']];
8         semaphore = 1;
9         semaphore_posts = 1;
10         timeListen;
12         use_offsite_archive = false;
13         window_displayed = false;
14         in_sequence = false;
15         tool_top_visible = false;
17         constructor(){
18                 super();
19                 this.init();
20         }
21                 
22         init():void{
23                 var board_uproces = window.location.pathname;
24                 this.board = board_uproces.substring(1, board_uproces.length - 1);
25                 this.activate();
26         }
27         
28         retrieveStates():void{
29                 this.use_offsite_archive =  localStorage.getItem("ArchiveType") == "0"  ? true : false;
30         }
31     storeStates(...items:any[]):void{}
32         activate():void{
33                 document.addEventListener("QRDialogCreation", (e) => this.enhance4ChanX());
34                 document.addEventListener('QRPostSuccessful', (e) => {
35                         if(this.in_sequence){
36                                 (<HTMLElement>document.getElementById("dump-list").childNodes[1]).click();
37                                 this.setPropperLinking((<HTMLInputElement>document.getElementById("qr").getElementsByTagName("TEXTAREA")[0]).value);
38                         }
39                 }, false);
40         }
41          
42         decideAction(node:any):void{}
44         enhance4ChanX():void{
45                 var qr_window = document.getElementById("qr");
47                 if(document.getElementById("qrRebuilder") !== null) qr_window.removeChild(document.getElementById("qrRebuilder"));
49                 var thread_rebuilder_table = document.createElement("TABLE");
50                 thread_rebuilder_table.setAttribute("id", "qrRebuilder");
51                 thread_rebuilder_table.setAttribute("style", "text-align:center");
52                 qr_window.appendChild(thread_rebuilder_table);
54                 var thread_row = document.createElement("TR");
55                 var option_text_size = 18;
56                 var help_icon_container = document.createElement("A");
57                 (<HTMLLinkElement>help_icon_container).href = "javascript:void(0)";
58                 help_icon_container.title = "Click to View Help!";
59                 var help_icon = document.createElement("IMG");
60                 help_icon.setAttribute("style", "height:" + option_text_size * 1.25 + "px;margin:-4px 10px");
61                 (<HTMLImageElement>help_icon).src = Constants.HELP_ICON_SOURCE;
63                 help_icon_container.appendChild(help_icon);
64                 thread_row.appendChild(help_icon_container);
66                 var tooltip_div = document.createElement("DIV");
67                 tooltip_div.innerHTML = "Insert the thread number of the post to rebuild<br/>Must be in either the 4chan archives or archived.moe<hr/>Submit bugs to <a href='https://github.com/ECHibiki/4chan-UserScripts'>my Github</a>";
68                 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
69                 help_icon_container.addEventListener("click", (evt)=>{
70                         if(this.tool_top_visible)
71                                 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:none;position:absolute;");
72                         else
73                                 tooltip_div.setAttribute("style", "z-index:9;padding:5px;border:1px solid black;background-color:white;word-wrap:break-word;display:block;position:absolute;"
74                                         + "left:" +  ((<MouseEvent>evt).clientX - (<DOMRect>qr_window.getBoundingClientRect()).x) +
75                                         "px;top:" +  ((<MouseEvent>evt).clientY - (<DOMRect>qr_window.getBoundingClientRect()).y ) + "px;");
76                         this.tool_top_visible = !this.tool_top_visible;
77                 });
78                 qr_window.appendChild(tooltip_div);
80                 var second_row_nodes = [
81                         document.createTextNode("Thread: "),
82                         document.createElement("INPUT"),
83                         document.createElement("INPUT"),
84                 ];
85                 second_row_nodes.forEach(
86                         (node) => {
87                                 thread_row.appendChild(node);
88                         });
89                 thread_rebuilder_table.appendChild(thread_row);
91                 (<HTMLInputElement>second_row_nodes[1]).setAttribute("ID", "threadInput");
92                 (<HTMLInputElement>second_row_nodes[1]).setAttribute("style", "width:35.0%");
94                 (<HTMLInputElement>second_row_nodes[2]).setAttribute("ID", "threadButton");
95                 (<HTMLInputElement>second_row_nodes[2]).setAttribute("type", "button");
96                 (<HTMLInputElement>second_row_nodes[2]).setAttribute("value", "Set Rebuild Queue");
98                 second_row_nodes[2].addEventListener("click", () => {
99                         this.in_sequence = true;
100                         this.killAll();
101                         this.getThread((<HTMLInputElement>second_row_nodes[1]).value);
102                         this.postID = setInterval(() => this.postRoutine(), 1000);
103                         if(this.timeListen === undefined) this.timeListen = setInterval(() => this.timeListenerFunction(), 1000);
104                 });
105                 qr_window.appendChild(document.createElement("hr"));
106         };
108         thread_data_length = 0;
109         posts_created = 0;
110         postID:number;
111         postRoutine():void{
112                 if(this.semaphore == 0){
113                         this.semaphore++;
114                         this.thread_data_length = this.thread_data[0].length;
115                         this.fillID = setInterval(() => this.fillRoutine(), 10);
116                         this.stopRoutine();
117                 }
118         };
120         stopRoutine():void{
121                 clearInterval(this.postID);
122         };
124         fillID:number;
125         fillRoutine():void{
126                 if (this.posts_created >= this.thread_data_length)
127                         { this.semaphore_posts = 0; this.stopFillRoutine(); }
128                 else if(this.semaphore_posts == 1){
129                         this.semaphore_posts--;
130                         this.createPost(this.thread_data[0][this.posts_created],
131                                 this.thread_data[1][this.posts_created],
132                                 this.thread_data[2][this.posts_created]);
133                         this.posts_created++;
134                 }
135         };
137         stopFillRoutine():void{
138                 clearInterval(this.fillID);
139         }
141         setPropperLinking (text):void{
142                 var search_regex = RegExp(">>\\d+", "g");
143                 var result;
144                 var index_old = -1;
145                 var link_arr = Array();
146                 while((result = search_regex.exec(text)) != null){
147                         var end_index = search_regex.lastIndex;
148                         var post_no = result.toString().replace(/>/g, "");
149                         link_arr.push([post_no, end_index]);
150                 }
151         //hunt down the text of what it linked to
152         //Get the links inside of the origonal message to show text contents
154                 var responding_text = Array();
155                 if(this.use_offsite_archive)
156                         var URL  = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + (<HTMLInputElement>document.getElementById("threadInput")).value;
157                 else
158                         var URL  = "https://a.4cdn.org/" + this.board + "/thread/" + (<HTMLInputElement>document.getElementById("threadInput")).value + ".json";
159                         var xhr = new GM_xmlhttpRequest(({
160                                 method: "GET",
161                                 url: URL,
162                                 responseType : "json",
163                                 onload: (data) => {
164                                         if(this.use_offsite_archive)
165                                                 data = data.response["" + (<HTMLInputElement>document.getElementById("threadInput")).value]["posts"];
166                                         else
167                                                 data = data.response["posts"];
168                                         if(data == undefined){
169                                                 alert("Invalid Thread ID: " + (<HTMLInputElement>document.getElementById("threadInput")).value + ". ");
170                                         }
171                                         else{
172                                                 link_arr.forEach((link_item)=>{
173                                                         for(var data_entry = 0 ; data_entry < data.length ; data_entry++){
174                                                                 if(parseInt(link_item[0]) == parseInt(data[data_entry]["no"])){
175                                                                         if(this.use_offsite_archive && data[data_entry]["comment_processed"] !== undefined)
176                                                                                 responding_text.push([ [post_no, end_index], data[data_entry]["comment_processed"].replace(/(&gt;&gt;|https:\/\/www\.archived\.moe\/.*\/thread\/.*\/#)\d+/g, ""), link_item["media"]["safe_media_hash"] ]);
177                                                                         else if(data[data_entry]["com"] !== undefined)
178                                                                                 responding_text.push([ [post_no, end_index], data[data_entry]["com"].replace(/(&gt;&gt;|#p)\d+/g, ""), data[data_entry]["md5"] ]);
179                                                                         else responding_text.push([ [post_no, end_index], undefined, data[data_entry]["md5"] ]);
180                                                                         break;
181                                                                 }
182                                                         }
183                                                 });
185                                                 var current_url = window.location.href;
186                                                 var hash_index = current_url.lastIndexOf("#") != -1 ? current_url.lastIndexOf("#"):  window.location.href.length;
187                                                 var current_thread = window.location.href.substring(current_url.lastIndexOf("/")+1, hash_index);
188                                                 var current_url =  "https://a.4cdn.org/" + this.board + "/thread/" + current_thread + ".json";
189                                                 //open current thread to hunt down the text found in links
190                                                 var xhr = new GM_xmlhttpRequest(({
191                                                         method: "GET",
192                                                         url: current_url,
193                                                         responseType : "json",
194                                                         onload: (data)=>{
195                                                                 data = data.response["posts"];
196                                                                 if(data == undefined){
197                                                                         alert("Invalid Thread ID: " + (<HTMLInputElement>document.getElementById("threadInput")).value + ". ");
198                                                                 }
199                                                                 else{
200                                                                         responding_text.forEach((response_item)=>{
201                                                                                 for(var data_entry = 0 ; data_entry < data.length ; data_entry++){
202                                                                                         if(data[data_entry]["com"] !== undefined && (response_item[1] == data[data_entry]["com"].replace(/(&gt;&gt;|#p)\d+/g, "") || response_item[1] == null)
203                                                                                                 && (response_item[2] == data[data_entry]["md5"] || response_item[2] == null)){
204                                                                                                 var start_index = response_item[0][0].legth - response_item[0][1];
205                                                                                                 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
206                                                                                                         break;
207                                                                                         }
208                                                                                         else if(response_item[2] !== undefined && response_item[2] == data[data_entry]["md5"]){
209                                                                                                                                                                                         var start_index = response_item[0][0].legth - response_item[0][1];
210                                                                                                 text = text.substring(0, start_index) + ">>" + data[data_entry]["no"] + text.substring(response_item[0][1]);
211                                                                                                         break;
212                                                                                         }
213                                                                                 }
214                                                                         });
215                                                                                                 (<HTMLInputElement>document.getElementById("qr").getElementsByTagName("TEXTAREA")[0]).value = text;
216                                                                                                 document.getElementById("add-post").click();
217                                                                                                 this.semaphore_posts++;
218                                                                 }
219                                                         }
220                                                 }));
221                                         }
222                                 }
223                         }));
225         };
228         //2) GET ARCHIVED THREAD
229         getThread(threadNo):void{
230                 this.thread_data = [[], [], [], []];
232                 if(this.use_offsite_archive)
233                         var URL  = "https://www.archived.moe/_/api/chan/thread/?board=" + this.board + "&num=" + (<HTMLInputElement>document.getElementById("threadInput")).value;
234                 else
235                         var URL  = "https://a.4cdn.org/" + this.board + "/thread/" + (<HTMLInputElement>document.getElementById("threadInput")).value + ".json";
236                 var xhr = new GM_xmlhttpRequest(({
237                         method: "GET",
238                         url: URL,
239                         responseType : "json",
240                         onload: (data) =>{
241                                 var starting_post = -1;
242                                 if(this.use_offsite_archive){
243                                         starting_post = 0;
244                                         data = data.response["" + (<HTMLInputElement>document.getElementById("threadInput")).value];
245                                 }
246                                 else{
247                                         starting_post = 1;
248                                         data = data.response;
249                                 }
250                                 if(data == undefined){
251                                         alert("Invalid Thread ID: " + threadNo + ".\n4chan Archive ");
252                                 }
253                                 else{
254                                         if(this.use_offsite_archive) data["posts"] = data.values(data["posts"]);
256                                         var len = data["posts"].length;
258                                         for(var post_number = starting_post ; post_number < len ; post_number++){
259                                                 var comment = undefined;
260                                                 if(this.use_offsite_archive)
261                                                         comment = data["posts"][post_number]["comment"];
262                                                 else
263                                                         comment = data["posts"][post_number]["com"];
264                                                 if(comment !== undefined && comment !== null)
265                                                         this.thread_data[0].push(comment);
266                                                 else
267                                                         this.thread_data[0].push("");
269                                                 var filename = undefined;
270                                                 if(this.use_offsite_archive){
271                                                         if(data["posts"][post_number]["media"] !== null)
272                                                                 filename = "" + data["posts"][post_number]["media"]["media_filename"];
273                                                 }
274                                                 else
275                                                         filename = "" + data["posts"][post_number]["tim"] + data["posts"][post_number]["ext"];
277                                                 if(filename !== undefined && filename !== null && filename.indexOf("undefined") == -1)
278                                                         if(this.use_offsite_archive)
279                                                                 if(data["posts"][post_number]["media"] !== null)
280                                                                         this.thread_data[1].push(data["posts"][post_number]["media"]["remote_media_link"]);
281                                                                 else  this.thread_data[1].push("");
282                                                         else
283                                                                 this.thread_data[1].push("https://i.4cdn.org/" + this.board + "/" + filename);
284                                                 else  this.thread_data[1].push("");
285                                                 if(this.use_offsite_archive){
286                                                         if(data["posts"][post_number]["media"] !== null)
287                                                                 this.thread_data[2].push(data["posts"][post_number]["media"]["media_id"]);
288                                                 }
289                                                 else
290                                                         this.thread_data[2].push(data["posts"][post_number]["filename"]);
292                                                 if(this.use_offsite_archive)
293                                                         this.thread_data[3].push(data["posts"][post_number]["num"]);
294                                                 else
295                                                         this.thread_data[3].push(data["posts"][post_number]["no"]);
296                                         }
297                                 }
298                                 this.semaphore--;
299                         }
300                 }));
301         };
302         //3) RIP POSTS AND IMAGES
303         createPost(text, imageURL, imageName):void{
304                 if(imageURL != ""){
305                         var response_type = "arraybuffer";
306                         if(this.use_offsite_archive) response_type = "text"
307                         var xhr = new GM_xmlhttpRequest(({
308                                 method: "GET",
309                                 url: imageURL,
310                                 responseType : response_type,
311                                 onload: (response) =>
312                                 {
313                                         if(this.use_offsite_archive){
314                                                 var parser = new DOMParser();
315                                                 var content_attribute = parser.parseFromString(response.response, "text/html").getElementsByTagName("META")[0].getAttribute("content");
316                                                 var redirect_url = content_attribute.substring(content_attribute.indexOf("http"));
317                                                 var xhr = new GM_xmlhttpRequest(({method:"GET", url: redirect_url, responseType:"arraybuffer",
318                                                         onload:(response) => {
319                                                                 this.inputImage(response, text,  imageURL, imageName);
320                                                         }
321                                                 }));
322                                         }
323                                         else{
324                                                 this.inputImage(response, text, imageURL, imageName);
325                                         }
326                                 }
327                         }));
328                 }
329                 else{
330                         text = this.createPostComment(text);
331                         this.setPropperLinking(text);
332                 }
333         }
335         inputImage(response, text, imageURL, imageName):void{
336                                         var blob;
337                                         var ext = ".jpg";
338                                         if(imageURL.indexOf(".jpg") > -1){
339                                                 blob = new Blob([response.response], {type:"image/jpeg"});
340                                                 ext = ".jpg";
341                                         }
342                                         else if(imageURL.indexOf(".png") > -1){
343                                                 blob = new Blob([response.response], {type:"image/png"});
344                                                 ext = ".png";
345                                         }
346                                         else if(imageURL.indexOf(".gif") > -1){
347                                                 blob = new Blob([response.response], {type:"image/gif"});
348                                                 ext = ".gif";
349                                         }
350                                         else if(imageURL.indexOf(".webm") > -1){
351                                                 blob = new Blob([response.response], {type:"video/webm"});
352                                                 ext = ".webm";
353                                         }
355                                         var name = imageName + ext;
357                                         //SEND RESULTING RESPONSE TO 4CHANX FILES === QRSetFile
358                                         var detail = {file:blob, name:name};
359                                                 detail  = cloneInto(detail , document.defaultView);
361                                         document.dispatchEvent(new CustomEvent('QRSetFile', {bubbles:true, detail}));
363                                         if(text !== "" && text !== undefined) {
364                                                 text = this.createPostComment(text);
365                                                 this.setPropperLinking(text);
366                                         }
367                                         else{
368                                                 document.getElementById("add-post").click();
369                                                 this.semaphore_posts++;
370                                         }
371         }
373         //4) CREATE POST QUEUE
374         createPostComment (text):string{
375                 var dummy = document.createElement("DIV");
376                 dummy.innerHTML = text;
377                 var inside_node = dummy.firstChild;
378                 var return_text = "";
379                 do{
380                         if((<HTMLElement>inside_node).tagName == "BR")
381                                 return_text += "\n";
382                         else
383                                 return_text += inside_node.textContent;
384                 }while((inside_node = inside_node.nextSibling));
386                 return return_text;
387         };
389         checked = false;
390         timeListenerFunction():void{
391                 var time = parseInt((<HTMLInputElement>document.getElementById("qr-filename-container").nextSibling).value.replace(/[a-zA-Z]+/g, ""));
392                 if(time  <= 5){
393                         this.checked = false;
394                 }
395                 else if(time > 5){
396                         this.checked = true;
397                 }
398         }
400         killAll():void{
401                 this.thread_data_length = 0;
402                 this.posts_created = 0;
403                 this.stopRoutine();
404                 this.postID = undefined;
405                 this.semaphore = 1;
406                 this.semaphore_posts = 1;
407                 this.stopFillRoutine();
408                 this.fillID  = undefined;
409                 this.thread_data = [['Comment'], ['Image URLs'], ['Image Names'] ,['Post No.']];
410                 //CLEAR DUMP LIST
411                 var qr_dumplist = document.getElementById("dump-list").childNodes;
412                 var qr_dumplist_len = qr_dumplist.length;
413                 var current_preview = 0;
414                 while(qr_dumplist_len - current_preview > 1){
415                         (<HTMLElement>qr_dumplist[0].firstChild).click();
416                         current_preview++;
417                 }
418         }