e621 Thumbnail Enhancer

Resizes thumbnails on e621.net, replacing them with higher resoltion images and adding support for video previews.

As of 2019-11-18. See the latest version.

  1. // ==UserScript==
  2. // @name e621 Thumbnail Enhancer
  3. // @version 1.01
  4. // @description Resizes thumbnails on e621.net, replacing them with higher resoltion images and adding support for video previews.
  5. // @author swordgedance
  6. // @include http://*e621.net/post*
  7. // @include https://*e621.net/post*
  8. // @include http://*e621.net/pool*
  9. // @include https://*e621.net/pool*
  10. // @grant GM.xmlHttpRequest
  11. // @namespace https://greasyfork.org/de/users/398891
  12. // ==/UserScript==
  13.  
  14. //original rooshoos
  15. //http://twitter.com/rooshoos
  16.  
  17.  
  18.  
  19. var sty =document.createElement("style");
  20. sty.innerHTML=[
  21. "div.thumbEnh_cont{"
  22. ," display: grid;"
  23. ," grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));"
  24. ,"}"
  25. ,"div.thumbEnh_cont span.thumb{"
  26. ," width:90%;"
  27. ," height:auto;"
  28. ,"}"
  29. ,"span.thumb img{"
  30. ," width:100%;"
  31. ," height:auto;"
  32. ,"}"
  33. // ,"span.thumb {"
  34. // ," width: 30%;" //auto;"
  35. // ," height: auto;" //250px;"
  36. // ," margin: 0 10px 10px 0;"
  37. // ,"}"
  38.  
  39. ,"span.thumb .preview {"
  40. ," display: block;"
  41. ," height: auto;"//220px;"
  42. ," width: 100%;"//auto;"
  43. ,"}"
  44.  
  45. ,"#child-posts-expanded-thumbs span.thumb,"
  46. ,"#child-posts-expanded-thumbs span.thumb .preview {"
  47. ," width: 32%;"//180px;"
  48. ," height:auto;"
  49. ,"}"
  50.  
  51. ,"span.thumb .post-score {"
  52. ," width: auto !important;"
  53. ,"}"
  54.  
  55. ,"span.thumb .tooltip-thumb {"
  56. ," display: block;"
  57. ," position: relative;"
  58. ,"}"
  59.  
  60. ,"span.thumb .gif,"
  61. ,"span.thumb .video {"
  62. ," position: relative;"
  63. ," display: block;"
  64. ,"}"
  65.  
  66. ,"span.thumb .gif:not(:hover)::after,"
  67. ,"span.thumb .video:not(:hover)::after {"
  68. ," content: '';"
  69. ," display: block;"
  70. ," position: absolute;"
  71. ," top: 0; bottom: 0; left: 0; right: 0;"
  72. ,"}"
  73.  
  74. ,"span.thumb .video:not(:hover)::after {"
  75. ," background: transparent "
  76. ," url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjA2IiBoZWlnaHQ9IjIwNiIgdmlld0JveD0iMCAwIDIwNiAyMDYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxjaXJjbGUgaWQ9ImIiIGN4PSI5MCIgY3k9IjkwIiByPSI5MCIvPjxmaWx0ZXIgeD0iLTUwJSIgeT0iLTUwJSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSIgZmlsdGVyVW5pdHM9Im9iamVjdEJvdW5kaW5nQm94IiBpZD0iYSI+PGZlT2Zmc2V0IGluPSJTb3VyY2VBbHBoYSIgcmVzdWx0PSJzaGFkb3dPZmZzZXRPdXRlcjEiLz48ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSI2LjUiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjI5NDE1NzYwOSAwIiBpbj0ic2hhZG93Qmx1ck91dGVyMSIvPjwvZmlsdGVyPjwvZGVmcz48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEzIDEzKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii44ODEiIGZpbGw9IiNGRkYiIHhsaW5rOmhyZWY9IiNiIi8+PC9nPjxwYXRoIGZpbGwtb3BhY2l0eT0iLjQiIGZpbGw9IiMwMDAiIGQ9Ik04MS41IDE0Ny42NThWNTkuMzQybDY1IDQ0LjE1OCIvPjwvZz48L3N2Zz4=)"
  77. ," no-repeat center/80px;"
  78. ,"}"
  79.  
  80. ,"span.thumb .gif:not(:hover)::after {"
  81. ," content: 'GIF';"
  82. ," width: 60px;"
  83. ," height: 30px;"
  84. ," margin: auto;"
  85. ," font-size: 16px;"
  86. ," font-weight: bold;"
  87. ," line-height: 30px;"
  88. ," color: rgba(0,0,0,0.4);"
  89. ," background-color: rgba(255,255,255,0.8);"
  90. ," border-radius: 6px;"
  91. ," box-shadow: 0 0 13px rgba(0,0,0,0.29);"
  92. ,"}"
  93.  
  94. ,"span.thumb .gif:hover .preview {"
  95. ," display: none !important;"
  96. ,"}"
  97.  
  98. ,"span.thumb .gif:hover img.preview {"
  99. ," display: block !important;"
  100. ,"}"
  101. ].join("");
  102. document.head.appendChild(sty);
  103.  
  104.  
  105. (function () {
  106. var contDiv = document.querySelector("span.thumb").parentElement;
  107. contDiv.className = "thumbEnh_cont";
  108.  
  109.  
  110. function is_gif(i) {
  111. return /^(?!data:).*\.gif/i.test(i.src);
  112. }
  113.  
  114. function freeze_gif(i) {
  115. var c = document.createElement('canvas');
  116. var w = c.width = i.naturalWidth;
  117. var h = c.height = i.naturalHeight;
  118. var p = i.parentNode;
  119. c.getContext('2d').drawImage(i, 0, 0, w, h);
  120. p.className = ['gif', p.className].join(' ');
  121. try {
  122. i.src = c.toDataURL("image/gif"); // if possible, retain all css aspects
  123. } catch (e) { // cross-domain -- mimic original with all its tag attributes
  124. replaceImg(c, i);
  125. i.style.display = 'none';
  126. p.insertBefore(i, p.firstChild);
  127. }
  128. }
  129.  
  130. function replaceImg(e, i) {
  131. e.className = i.className;
  132. var s = window.getComputedStyle(i);
  133. e.style.border = s.getPropertyValue('border');
  134. e.style.borderRadius = s.getPropertyValue('border-radius');
  135. i.parentNode.replaceChild(e, i);
  136. }
  137.  
  138. function setVideo(thumb, videoUrl) {
  139. var video = document.createElement('video'),
  140. parent = thumb.parentNode;
  141. video.controls = false;
  142. video.loop = true;
  143. video.muted = true;
  144. video.preload = 'metadata';
  145. video.addEventListener('loadedmetadata', function () {
  146. parent.className = ['video', parent.className].join(' ');
  147. parent.addEventListener('mouseenter', function () {
  148. video.play();
  149. });
  150. parent.addEventListener('mouseleave', function () {
  151. video.pause();
  152. });
  153. replaceImg(this, thumb);
  154. }, false);
  155. video.src = videoUrl;
  156. }
  157.  
  158. /* Replace video thumbnails with actual playable video */
  159. function videoThumb(thumb, parseHTML) {
  160. parseHTML = parseHTML || false;
  161. var parent = thumb.parentNode;
  162.  
  163. GM.xmlHttpRequest({
  164. method: "GET",
  165. url: parent.href,
  166. headers: {
  167. "Accept": "text/xml"
  168. },
  169. onload: function (response) {
  170. var videoUrl = null;
  171. if (response.readyState !== 4) return;
  172. if (!response.responseXML) return;
  173.  
  174. var file_url = response.responseXML.getElementsByTagName('file_url')[0];
  175. if (!file_url) return;
  176.  
  177. videoUrl = file_url.childNodes[0].nodeValue;
  178. setVideo(thumb, videoUrl);
  179. }
  180. });
  181.  
  182. }
  183.  
  184. /* Replace image thumbnails with higher resolution */
  185. function imageThumb(thumb) {
  186. var newThumb = new Image(),
  187. replace = function (thumb) {
  188. thumb.src = this.src;
  189. if (is_gif(thumb)) {
  190. //freeze_gif(thumb);
  191. }
  192. },
  193. trynoSample = function (thumb) {
  194. this.onerror = tryGif.bind(this, thumb);
  195. this.src = thumb.src.replace('/preview/', '/');
  196.  
  197. },
  198. tryGif = function (thumb) {
  199. this.onerror = null;
  200. this.src = thumb.src.replace('/preview/', '/').replace('.jpg', '.gif');
  201. };
  202. newThumb.onload = replace.bind(newThumb, thumb);
  203. newThumb.onerror = trynoSample.bind(newThumb, thumb);
  204. newThumb.src = thumb.src.replace('/preview/', '/sample/');
  205. }
  206.  
  207. function imgError(image) {
  208. image.onerror = "";
  209. image.src = "/images/noimage.gif";
  210. return true;
  211. }
  212.  
  213. /* Run above on all thumbnails */
  214. var thumbs = document.querySelectorAll('span.thumb img');
  215. //var typ=document.querySelectorAll('span.thumb span.type-badge');
  216. for (i = 0; i < thumbs.length; i++) {
  217. var thumb = thumbs[i];
  218. var badge = thumb.parentElement.querySelector("span.type-badge");
  219. if (badge && badge.innerHTML.toLowerCase() == "webm") {
  220. (function (thumb, i) {
  221. setTimeout(function () {
  222. videoThumb(thumb);
  223. }, 100 * i);
  224. })(thumb, i);
  225. } else {
  226.  
  227. imageThumb(thumb);
  228.  
  229. }
  230. }
  231. })();