Made 'Past' links open in a new window
[imgurfusker.git] / ImgurFusker.html
blob6aea1012093b09017d3e1c87122ea928b98323df
1 <!DOCTYPE html>
2 <html data-VERSION='0.1'>
3 <!--
4 ***************** ImgurFusker version 0.1 *****************
5 *********** http://repo.or.cz/w/imgurfusker.git ***********
6 ******** imgurfusker@hmamail.com (expires 7/3/14) *********
7 **************** Written on July 4th, 2014. ***************
8 *********** God bless America. God bless nudes. ***********
10 ~~~ ABOUT ~~~
12 This is a small utility to automatically search for nudes on Imgur via a brute force method.
13 (This is known as "fusking").
15 It was inspired by http://noisediary.com/.
17 I also refer to nudes as "nuuus" throughout this page because I don't fucking feel like putting 'nudes' everywhere.
18 Deal with it.
20 ~~~ DEPEDENCIES ~~~
22 The code was originally ripped right from NoiseDiary, but since then it has been heavily
23 modified and rewritten. Honestly, the person who wrote NoiseDiary can't fucking code anyway.
25 This page uses jQuery. If you don't know what jQuery is then fuck off.
27 The image detection is done by a library known as nude.js.
28 https://github.com/pa7/nude.js
30 ~~~ QUESTIONS ~~~
32 Q: Why did you do this?
33 A: Hello? Fucking nudes.
35 Q: Why does it keep finding non-nudes and skip B&W nudes?
36 A: Because fuck you, that's why. I didn't write the library.
37 You think you can do better? Go write a better library and come back to me. I'll use your library.
39 Q: Why is it freezing up my computer? You fucking suck at this.
40 A: No YOU suck. Scanning the image is resource intensive and can freeze your browser if the FAIL_TIME option is set too low.
42 ~~~ Contributing ~~~
44 Because of the nature of the project, it is developed and hosted entirely anonymously.
46 1. Fucking get permission from me first.
48 And learn how to use Git if you don't already.
50 2. Generate an SSH key.
52 If you don't know how, google it. I'm going to hold your fucking hand, especially if you're a Windows user.
54 3. Register an "account" at http://repo.or.cz/reguser.cgi
56 Your email doesn't even have to be legit, though I would recommend at least using a temporary one from
57 https://securemail.hidemyass.com/ in case you need to change your SSH key.
59 4. Clone the project
61 Command is: git clone git://repo.or.cz/imgurfusker.git
63 5. Inside the project directory, edit the config file at .git/config
65 Add this to the end, substituting your own info where noted:
67 [user]
68 name = 'Anonymous'
69 email = '<YOUR_HMA_EMAIL_OR_LEAVE_BLANK>'
70 [remove "origin"]
71 url = ssh://<YOUR_ORCZ_USERNAME>@repo.or.cz/srv/git/imgurfusker.git
72 fetch = +refs/heads/*:refs/remotes/origin/*
76 ~~~ LICENSING BULLSHIT ~~~
78 This program is free software. It comes without any warranty, to
79 the extent permitted by applicable law. You can redistribute it
80 and/or modify it under the terms of the Do What The Fuck You Want
81 To Public License, Version 2, as published by Sam Hocevar. See
82 http://www.wtfpl.net/ for more details.
84 -->
85 <head>
86 <meta http-equiv="content-type" content="text/html; charset=UTF-8">
87 <meta charset="utf-8">
88 <meta http-equiv="X-UA-Compatible" content="IE=edge">
89 <meta name="viewport" content="width=device-width, initial-scale=1.0">
90 <meta name="description" content="">
91 <meta name="author" content="">
93 <title>ImgurFusker</title>
94 <link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,600,600italic,700,700italic">
95 <style>
96 body {
97 font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;
99 @media (min-width: 1200px) { /* Large desktop */
100 body { padding: 0 50px; }
103 @media (min-width: 768px) and (max-width: 1199px) { /* Portrait tablet to landscape and desktop */
104 body { padding: 0 30px; }
107 @media (max-width: 767px) { /* Landscape phone to portrait tablet */
108 body { padding: 0 20px; }
111 @media (max-width: 480px) { /* Landscape phones and down */
112 body { padding: 0 5px; }
115 h1 {
116 font-size: 2.7em;
117 margin: .2em .4em;
118 font-family: 'Open Sans','Courier';
119 font-weight: 100;
121 h1 small {
122 font-size: .3em;
124 h2 {
125 font-size: 2.3;
126 font-family: 'Open Sans','Courier';
127 font-weight: 400;
128 margin: 0;
131 a:hover, a:visited, a:link, a:active {
132 text-decoration: none;
135 img {
136 vertical-align: text-bottom;
139 .btn {
140 display: inline-block;
141 margin-bottom: 0px;
142 font-weight: normal;
143 text-align: center;
144 vertical-align: middle;
145 cursor: pointer;
146 background-image: none;
148 white-space: nowrap;
149 padding: 0.5em 1em;
150 font-size: 1em;
151 line-height: 1;
153 color: #333;
154 background-color: #E7E7E7;
155 border: 1px solid #DADADA;
157 .btn:hover {
158 background-color: #DADADA;
160 .btn-block {
161 display: block;
162 width: 100%;
163 padding: 1em 2em;
166 #images {
167 margin: 20px 0;
170 .thumb-container {
171 display:inline-block;
172 position:relative;
173 overflow:show;
174 min-height:110px;
175 min-width:110px;
176 clear:both;
178 .thumb {
179 height: 110px;
180 width: 110px;
183 #images img {
184 margin-right: 5px;
185 border: 2px solid transparent;
187 #images img:hover, .delort:hover{
188 border-color: #ff0000;
191 .sauce, .delort {
192 z-index:1000;
193 height:16px;
194 width:16px;
195 position:absolute;
196 padding:0px;
198 .sauce {
199 bottom:10px;
200 margin-right: 0;
201 right:12px;
203 .delort {
204 right:7px;
205 border: 2px solid transparent;
206 font-weight: bold;
207 font-size: 20px;
208 text-align:center;
209 cursor: pointer;
210 line-height:.6;
211 background-color: #333;
213 .delort, .delort:focus, .delort:hover {
214 color: red;
216 .delort:hover {
217 border-color: #ff0000;
220 #examining {
221 font-weight: 100;
222 font-size: 20px;
224 #examining i {
225 font-style: italic;
226 color: #888;
229 #current {
230 text-align:center;
231 height: 340px;
232 background-color: #FFFFE0;
234 #current img {
235 max-height: 300px;
236 max-width: 400px;
239 #cache-popup {
240 position: absolute;
241 display: block;
242 min-height: 100px; //adjust as per need
243 min-width: 350px; //adjust as per need
244 z-index: 200;
245 background: white;
246 top: 150px;
247 border: 2px solid #999;
248 border-radius: 10px 10px;
249 padding: 15px;
250 width: 600px;
251 left: 0;
252 right: 0;
253 margin: auto;
256 </style>
261 </head>
263 <body>
264 <h1>ImgurFusker</h1>
266 <button id="bigass-button" class="btn btn-block">Start!</button>
268 <div id="current">
269 <h4 id="examining"></h4>
270 <img id="current-img">
271 </div>
273 <div id="images"></div>
275 <div onclick='document.getElementById("cache-popup").style.visibility="visible";' class="btn" style="float: right">
276 Past
277 </div>
278 <div id="cache-popup" style="visibility: hidden;" >
279 <button onclick='document.getElementById("cache-popup").style.visibility="hidden";' class="btn" style="float:right; padding:0 2px; font-weight:100">x</button>
280 <h2>Past Images</h2>
281 <div id="cache-images">
282 </div>
283 </div>
285 <div class='thumb-container' id='img-template' style="display:none">
286 <a href='' target='_blank' class='thumb'>
287 <img src='' class=''>
288 </a>
289 <span class='delort'>x</span>
290 <a href='' class='sauce' target='_blank' rel='noreferrer' alt='original imgur page'>
291 <img src='http://imgur.com/favicon.ico'>
292 </a>
293 </div>
294 <canvas id="myCvs" style="display:none"></canvas>
295 <!-- Popup itself -->
297 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
298 <script src="nude.js" type="text/javascript"></script>
299 <script src="worker.nude.js" type="text/javascript"></script>
300 <!--<script src="noworker.nude.js" type="text/javascript"></script>-->
303 <script type="text/javascript">
306 var VERSION = $(document.getElementsByTagName("html")[0]).data('version')
308 var opt = {
309 DEBUG: false, // Will flag EVERY image as a nuuu.
310 FAIL_TIME: 500, // How long to wait, in ms, between tries (NOTE: Setting this too low may cause your browser to freeze)
311 SUCCESS_TIME: 10000, // How long to wait, in ms, after finding a nuuu to continue searching (This is just for you to look at the nuuu.)
312 STOP_WHEN_FIND: false, // Whether or not to automatically stop after
313 SCAN_THUMBNAILS: false, // Scan the thumbnail instead of the full image. Will be a lot faster, but will lead to MANY more false positives.
314 SHOW_CURRENT: true, // Whether or not to show the image currently being scanned.
317 var imgurcache = new Array();
319 var thumb_link = function(id) { return 'http://i.imgur.com/'+id+'s.png'}
320 var img_link = function(id) { return 'http://i.imgur.com/'+id+'.jpg'}
323 $('h1').append(" v" + VERSION);
324 document.title = document.title + " v" + VERSION;
325 if(opt.DEBUG)
326 $('h1').append("<small style='color:red; font-size:.3em;'>Debug mode</small>");
327 if(!opt.SHOW_CURRENT) {
328 $('#current').css('height', 'auto');
329 $('#current img').css('display', 'none');
334 var Imgur = {
335 stop: false,
336 status: function(txt, clr) {
337 $('#examining').text(txt);
338 $('#examining').css('color', clr);
339 console.log(txt);
342 hunt: function() {
343 var self=this;
344 console.log(self.stop());
345 if(self.stop())
346 return;
348 var id = self.random(5),
349 img = new Image;
350 img.crossOrigin = "Anonymous";
352 function fail(fail_id, fail_reason) {
354 self.status("Checked " + fail_id + ". " + fail_reason, '#333')
355 if(self.stop())
356 return;
357 setTimeout(function(){self.hunt()}, opt.FAIL_TIME);
359 img.onerror = fail;
360 img.onload = function() {
361 // PHASE 1: Look for an actual image
362 if ((img.width==198 && img.height==160) || (img.width==161 && img.height==81)) {
363 // assume this is an imgur error image, and retry.
364 fail(id, "Hunting for next image...");
365 } else {
367 //We've found AN image; now to do the actual checking
368 $('#cache-images').append('<a target="_blank" href="'+img_link(id)+'"><img src="'+thumb_link(id)+'"></a>');
370 var cvs = document.getElementById('myCvs'),
371 ctx = cvs.getContext('2d');
372 cvs.height = img.height;
373 cvs.width = img.width;
374 ctx.drawImage( img, 0, 0);
375 var datum = cvs.toDataURL();
379 var img2 = document.getElementById('current-img');
380 img2.onerror = function(wat) {
381 self.status("A horrible error occurred during Phase 2.", 'red')
382 if(self.stop())
383 return;
384 console.log(wat);
386 img2.onload = function() {
387 self.status("Checking " + id + " for nuuity", '#000');
388 if(self.stop())
389 return;
390 nude.load(img);
391 if(self.stop())
392 return;
393 nude.scan(function(is_nude){
394 if(is_nude || opt.DEBUG)
395 self.found(id);
396 else
397 fail(id, "Not a nude.");
400 self.status("Checking " + id, '#000')
401 if(self.stop())
402 return;
403 img2.src = datum;
405 }; // </onload>
406 if(opt.SCAN_THUMBNAILS)
407 img.src = thumb_link(id);
408 else
409 img.src = img_link(id);
410 }, // </hunt>
411 found: function(id) {
412 var self=this;
414 var new_node = $('#img-template').clone();
415 new_node.css('display', 'inline');
416 new_node.attr('id', "thumb" + id);
417 new_node.find('.thumb').attr("href", img_link(id));
418 new_node.find('.thumb img').attr("src", thumb_link(id));
419 new_node.find('.thumb img').addClass("thumb" + id);
420 new_node.find('.sauce').attr('href', "http://imgur.com/" + id);
421 new_node.find('.delort').click(function() { $(this).parent().remove() });
422 $('#images').append(new_node);
424 self.status("Aw yiss, found a nuuu at " + id, '#3c0');
425 if(self.stop(true))
426 return;
427 if(!(opt.SUCCESS_TIME>0)) {
428 self.hunt();
429 return;
431 // Wait a few seconds so we can view the nuuu
432 var until = opt.SUCCESS_TIME;
433 $('#examining').append(' <b>' + (until/100) + '</b>');
434 var until_f = function() {
435 if(self.stop()) {
436 $('#examining b').remove();
437 return;
440 until-=100;
441 if(until<0)
442 self.hunt();
443 else {
444 $('#examining b').text((until/100));
445 console.log("Starting again in " + until);
446 setTimeout(until_f, 100);
449 setTimeout(until_f, 100);
451 random: function(len) {
452 var text = new Array();
453 var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
454 for (var i=0; i < len; i++) {
455 imgurchar = possible.charAt(Math.floor(Math.random() * possible.length));
456 possible.replace(imgurchar, '');
457 text.push(imgurchar);
459 text = text.join('');
460 if (imgurcache.indexOf(text) == -1) {
461 imgurcache.push(text);
462 return text;
463 } else {
464 self.random(5);
465 return false;
468 start: function(e) {
469 console.log("The hunt is on");
470 self.stop_plz = false; //gooby, pls
471 Imgur.hunt();
472 $('#bigass-button').unbind('click', self.start);
473 $('#bigass-button').bind('click', function() {
474 console.log("Stopping");
475 self.stop_plz = true;
477 $('#examining i').remove();
478 $("#bigass-button").text("Stop");
480 stop: function(nuuu_obtained) {
481 if(self.stop_plz || (nuuu_obtained!=undefined && opt.STOP_WHEN_FIND)) {
482 if($('#examining i').remove())
483 $('#examining').prepend("<i>[Stopped]</i> ");
484 $("#bigass-button").text("Resume");
485 $("#bigass-button").unbind('click', self.stop);
486 $("#bigass-button").bind('click', Imgur.start);
487 return true;
489 return false;
492 $('#bigass-button').click(Imgur.start);
493 </script>
495 </body>
496 </html>