Sleazy Fork is available in English.

Apina.biz improved

Browse apina.biz with full-sized images. Plus other tweaks.

  1. // ==UserScript==
  2. // @name Apina.biz improved
  3. // @namespace Rennex/apina.biz
  4. // @description Browse apina.biz with full-sized images. Plus other tweaks.
  5. // @include /https?://apina\.biz//
  6. // @version 3.0
  7. // @run-at document-start
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. const randoms_cache_days = 7
  12.  
  13. const randoms_cache_ms = randoms_cache_days*24*3600*1000
  14.  
  15. var m
  16. if (m = location.href.match(/apina\.biz\/(\d+\.(jpg|gif|png|webm|mp4))/)) {
  17. // we've landed on the zoom-in page from an external link
  18. // -> redirect to the full-sized picture
  19. location.replace("https://images.apina.biz/full/" + m[1])
  20. return
  21. }
  22. // also remove that ?ref=randoms bullshit from the address bar
  23. if (m = location.href.match(/apina\.biz\/(.+)\?ref=/)) {
  24. history.replaceState(null, "", m[1])
  25. }
  26.  
  27. // hide the main picture and randoms list asap
  28. var style = document.createElement("style")
  29. style.type = "text/css"
  30. style.innerHTML = "#big_image, #randoms { display: none; }"
  31.  
  32. // the <head> might not exist at this point
  33. var head = document.head
  34. if (!head) {
  35. head = document.createElement("head")
  36. document.children[0].appendChild(head)
  37. }
  38. head.appendChild(style)
  39.  
  40.  
  41. function addZoomIndicator(img, parent, event) {
  42. var handler = function() {
  43. // only handle this event once
  44. img.removeEventListener(event, handler)
  45.  
  46. var zoom = document.createElement("small")
  47. zoom.style.color = "#888"
  48.  
  49. // update the percentage when the window is resized
  50. var updateZoom = function() {
  51. // if it's a video, we must use clientWidth and hope that the borders are always 6 px
  52. var displayw = img.width || (img.clientWidth - 6)
  53. var realw = img.naturalWidth || img.videoWidth
  54.  
  55. // calculate the size in physical pixels for high DPI screens
  56. var dpr = window.devicePixelRatio || 1
  57. var ratio = dpr * displayw / realw
  58.  
  59. // show the zoom indicator only if it's shrunken in physical pixels
  60. zoom.textContent = (ratio >= 1) ? "" : Math.floor(ratio*100).toString() + "%"
  61.  
  62. // if it's not shrunken in logical pixels, remove the hover effect and finger cursor
  63. if (displayw == realw) {
  64. img.style.background = "#fff"
  65. img.style.cursor = "default"
  66. }
  67. else {
  68. img.style.background = ""
  69. img.style.cursor = ""
  70. }
  71. }
  72. window.addEventListener("resize", updateZoom)
  73. updateZoom()
  74. parent.appendChild(zoom)
  75. }
  76. img.addEventListener(event, handler)
  77. }
  78.  
  79.  
  80. addEventListener("DOMContentLoaded", function () {
  81. try {
  82. // if we are in the image browsing mode, viewing a medium-sized image,
  83. // this will find an element
  84. var m, img, video, a
  85. if (a = document.querySelector("#big_image a")) {
  86. if (m = a.href.match(/\/\d+[^\/]+$/)) {
  87. // fix the link to point directly to the image
  88. a.href = "//images.apina.biz/full" + m[0]
  89. // and remove that annoying title popup while we're at it
  90. a.removeAttribute("title")
  91.  
  92. var parent = a.parentElement
  93.  
  94. // change the img element to use the full-sized image and appear wider
  95. if (img = a.querySelector("img")) {
  96. // we have to remove this image and create a new one,
  97. // to prevent it from visibly growing moments later
  98. a.removeChild(img)
  99. img = new Image()
  100. addZoomIndicator(img, parent, "load")
  101. img.src = a.href
  102. img.style.maxWidth = "100%"
  103. a.appendChild(img)
  104. }
  105. else if (video = a.querySelector("video")) {
  106. // webm/mp4 video instead?
  107. // let it auto-size
  108. video.removeAttribute("width")
  109. video.removeAttribute("height")
  110. video.style.maxWidth = "100%"
  111.  
  112. // to enable pausing and other controls, move it outside the <a>
  113. parent.removeChild(a)
  114.  
  115. // we need a new <video> element, the old one's events may have fired
  116. var newvideo = video.cloneNode(false)
  117.  
  118. // "canplay" seems to fire at a time when the video element size has settled
  119. addZoomIndicator(newvideo, parent, "canplay")
  120.  
  121. // replace small sources with full-sized ones
  122. for (var source of video.querySelectorAll("source")) {
  123. var newsource = source.cloneNode(false)
  124. newsource.src = source.src.replace(/medium\/m_/, "full/")
  125. newvideo.appendChild(newsource)
  126. }
  127. parent.appendChild(newvideo)
  128. }
  129. }
  130. }
  131.  
  132. // handle the randoms memory
  133. if (m = location.href.match(/apina\.biz\/(\d+)$/)) {
  134. var pic = m[1]
  135. var randoms = document.getElementById("randoms")
  136. var stored = localStorage.getItem(pic)
  137. if (stored) {
  138. try {
  139. stored = JSON.parse(stored)
  140. randoms.innerHTML = stored.randoms
  141. console.log("restored randoms from cache")
  142. }
  143. catch (e) { }
  144. }
  145. localStorage.setItem(pic, JSON.stringify({
  146. time: Date.now(),
  147. randoms: randoms.innerHTML
  148. }))
  149. }
  150. }
  151. finally {
  152. // re-enable displaying the picture and randoms bar
  153. head.removeChild(style)
  154. }
  155.  
  156. }, false)
  157.  
  158. // if it's been too long since the last cleanup of the randoms cache, do it now
  159. var lastcleanup = parseInt(localStorage["lastcleanup"])
  160. if (!lastcleanup || lastcleanup < Date.now() - 0.1*randoms_cache_ms) {
  161. localStorage["lastcleanup"] = Date.now()
  162.  
  163. console.log("cleaning randoms cache")
  164. for (var key of Object.keys(localStorage)) {
  165. if (key.match(/^\d+$/)) {
  166. var keep = false
  167. try {
  168. var stored = JSON.parse(localStorage.getItem(key))
  169. if (stored.time > Date.now() - randoms_cache_ms) {
  170. keep = true
  171. }
  172. }
  173. catch (e) { }
  174.  
  175. if (!keep) {
  176. localStorage.removeItem(key)
  177. console.log("flushed " + key + " from localStorage")
  178. }
  179. }
  180. }
  181.  
  182. }