Sleazy Fork is available in English.

4chan Archive Image Expander

Adds inline image expansion to 4chan archives.

Pada tanggal 20 November 2019. Lihat %(latest_version_link).

  1. // ==UserScript==
  2. // @name 4chan Archive Image Expander
  3. // @description Adds inline image expansion to 4chan archives.
  4. // @author Hen-Tie
  5. // @homepage http://hen-tie.tumblr.com/
  6. // @namespace https://greasyfork.org/en/users/8336
  7. // @include /https?:\/\/(desuarchive\.org|archived\.moe)\/.*\/thread\/.*/
  8. // @include /https?:\/\/thebarchive\.com\/(b|bant|talk)\/.*/
  9. // @grant none
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
  11. // @require https://greasyfork.org/scripts/39415-jquery-initialize/code/jQuery%20Initialize.js?version=258071
  12. // @icon https://i.imgur.com/80UFdoW.png
  13. // @version 1.8
  14. // ==/UserScript==
  15. var jq = jQuery.noConflict(true);
  16. (function ($) {
  17. //index all images for modal gallery
  18. var fullImage = [];
  19. var thumbnail = [];
  20. var galleryActivated = 0;
  21.  
  22. $("body").append('<modal id="aie"><div id="aie-img-controls">Image Size: <a id="aie-img-native" href="javascript:;">Native</a> | <a id="aie-img-fill" href="javascript:;">Fill</a> | <a id="aie-img-fit" href="javascript:;">Fit</a></div></modal>');
  23.  
  24. //gallery mode keypress listener
  25. $("body").on("keydown", function(e) {
  26. //g to open
  27. if (e.which == 71) {
  28. if (galleryActivated) {
  29. $('modal').show();
  30. } else {
  31. $('modal').show();
  32. $('a.thread_image_link').each(function() {
  33. fullImage.push('<img src="' + $(this).attr('href') + '" />');
  34. thumbnail.push('<img src="' + $(this).children('img').attr('src') + '" />');
  35. });
  36. $.each(fullImage, function(i) {
  37. $("modal").append(fullImage[i]);
  38. });
  39. galleryActivated = 1;
  40. }
  41. }
  42. //esc to close
  43. if (e.which == 27) {
  44. $('modal').hide();
  45. }
  46. });
  47.  
  48. //gallery image contorls
  49. $('#aie-img-native').click(function() {
  50. //$('modal img').each(function() {
  51. // $(this).css({'width':'auto','max-width':'unset'});
  52. //});
  53. imgFit(this);
  54. });
  55. function imgFit(x) {
  56. console.log(x);
  57. }
  58. $('#aie-img-fill').click(function() {
  59. $('modal img').each(function() {
  60. $(this).css({'width':'100%','max-width':'unset'});
  61. });
  62. });
  63. $('#aie-img-fit').click(function() {
  64. $('modal img').each(function() {
  65. $(this).css({'width':'unset','max-width':'100%'});
  66. });
  67. });
  68.  
  69. //catches image load event
  70. $.initialize('.init', function() {
  71. $(this).parent().removeClass('spinner');
  72. });
  73.  
  74. //insert download image links
  75. $('.post_file_filename').each(function() {
  76. $(this).attr('download',true);
  77. });
  78.  
  79. $('<style type="text/css">.spinner:before{content:"";box-sizing:border-box;position:absolute;top:50%;left:50%;width:20px;height:20px;margin-top:-10px;margin-left:-10px;border-radius:50%;border-top:2px solid #CCC;border-right:2px solid transparent;animation:spinner 0.6s linear infinite}@keyframes spinner{to{transform:rotate(360deg)}}</style>').appendTo('head');
  80. $('<style type="text/css">#aie-img-controls{width:100%;background:#282a2e;padding:0 1em;line-height:2;position:fixed;}modal img{display:block;margin-top:2em;}modal{display:none;position:fixed;top:0;left:0;overflow:auto;width:100%;height:100%;background:#1d1f21;}</style>').appendTo("head");
  81.  
  82. //video settings
  83. var vidAttr = 'loop autoplay controls';
  84. var imgCSS = {
  85. 'max-width': '100%',
  86. 'height': 'auto'
  87. };
  88. var webmCSS = {
  89. 'max-width': '100%',
  90. 'height': 'auto'
  91. };
  92. //indicate webm thumbnail
  93. $('.post_file_filename[href$=".webm"]').parent().next().find('.post_image').css('border', '3px solid #5f89ac');
  94.  
  95. //prevent weird wrapping around expanded images
  96. $('.theme_default .post header').css('display', 'inline-block');
  97.  
  98. $('.thread_image_box a').on('click', function (e) {
  99. var myHref = $(this).attr('href');
  100. var myHeight = $(this).children('img').outerHeight();
  101. var myWidth = $(this).children('img').outerWidth();
  102. $(this).parent().addClass('spinner').css({
  103. 'min-height': myHeight,
  104. 'min-width': myWidth,
  105. 'position': 'relative'
  106. });
  107.  
  108. //new elements containing full size href as src
  109. var img = $('<img />').attr({
  110. 'src': myHref,
  111. 'class': 'openItem'
  112. }).css(imgCSS).load(function(){
  113. $(this).addClass('init');
  114. });
  115.  
  116. var webm = $('<video style="background-color: #222;" poster="data:image/gif,AAAA" ' + vidAttr + ' id="vid"><source type="video/webm" src="' + myHref + '"/></video>').attr('class', 'openItem').css(webmCSS);
  117. //check filetype, hide thumbnail, insert full size file
  118. if (myHref.match(/.gif$|.png$|.jpg$/g)) {
  119. e.preventDefault();
  120. $(this).fadeTo('fast', 0, function () {
  121. $(this).hide();
  122. $(this).after(img);
  123. });
  124. } else if (myHref.match(/.webm$/g)) {
  125. e.preventDefault();
  126. $(this).hide();
  127. $(this).after(webm);
  128. var vid = document.getElementById("vid");
  129. //video proven to be loadable, cancel spinner
  130. vid.ondurationchange = function() {
  131. $(this).parent().removeClass('spinner');
  132. };
  133. } else {
  134. console.log('"4chan Archive Image Expander"\nUnsupported filetype, please report.\nSee @homepage or @namespace for contact info.');
  135. }
  136. //if src is broken insert placeholder, stop infinite spinner
  137. setTimeout(function(){
  138. var checkBroken = $('.openItem');
  139. if (checkBroken.width() === 16 && checkBroken.height() === 16) {
  140. checkBroken.addClass('init').attr('src','http://via.placeholder.com/'+myWidth + 'x' + myHeight+'/1d1f21/888888?text=ERR.');
  141. console.log('broken image');
  142. } else if (checkBroken.is('video')) {
  143. //if readyState has no metadata
  144. if (vid.readyState === 0) {
  145. checkBroken.addClass('init');
  146. console.log('broken video');
  147. }
  148. } else {
  149. return false;
  150. }
  151. }, 3000);
  152. });
  153.  
  154. //on reclick, remove full size, show thumbnail again
  155. $(document).on('click', '.openItem', function () {
  156. //video not loaded or timed out, remove spinner on close
  157. if ($(this).is('video')) {
  158. $(this).parent('.spinner').removeClass('spinner');
  159. }
  160. $(this).prev().show().fadeTo(0, 1);
  161. $(this).remove();
  162. });
  163. }(jq));