Apina.biz improved

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

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name        Apina.biz improved
// @namespace   Rennex/apina.biz
// @description Browse apina.biz with full-sized images. Plus other tweaks.
// @include     /https?://apina\.biz//
// @version     3.0
// @run-at      document-start
// @grant       none
// ==/UserScript==

const randoms_cache_days = 7

const randoms_cache_ms = randoms_cache_days*24*3600*1000

var m
if (m = location.href.match(/apina\.biz\/(\d+\.(jpg|gif|png|webm|mp4))/)) {
    // we've landed on the zoom-in page from an external link
    // -> redirect to the full-sized picture
    location.replace("https://images.apina.biz/full/" + m[1])
    return
}
// also remove that ?ref=randoms bullshit from the address bar
if (m = location.href.match(/apina\.biz\/(.+)\?ref=/)) {
    history.replaceState(null, "", m[1])
}

// hide the main picture and randoms list asap
var style = document.createElement("style")
style.type = "text/css"
style.innerHTML = "#big_image, #randoms { display: none; }"

// the <head> might not exist at this point
var head = document.head
if (!head) {
    head = document.createElement("head")
    document.children[0].appendChild(head)
}
head.appendChild(style)


function addZoomIndicator(img, parent, event) {
    var handler = function() {
        // only handle this event once
        img.removeEventListener(event, handler)

        var zoom = document.createElement("small")
        zoom.style.color = "#888"

        // update the percentage when the window is resized
        var updateZoom = function() {
            // if it's a video, we must use clientWidth and hope that the borders are always 6 px
            var displayw = img.width || (img.clientWidth - 6)
            var realw = img.naturalWidth || img.videoWidth

            // calculate the size in physical pixels for high DPI screens
            var dpr = window.devicePixelRatio || 1
            var ratio = dpr * displayw / realw

            // show the zoom indicator only if it's shrunken in physical pixels
            zoom.textContent = (ratio >= 1) ? "" : Math.floor(ratio*100).toString() + "%"

            // if it's not shrunken in logical pixels, remove the hover effect and finger cursor
            if (displayw == realw) {
                img.style.background = "#fff"
                img.style.cursor = "default"
            }
            else {
                img.style.background = ""
                img.style.cursor = ""
            }
        }
        window.addEventListener("resize", updateZoom)
        updateZoom()
        parent.appendChild(zoom)
    }
    img.addEventListener(event, handler)
}


addEventListener("DOMContentLoaded", function () {
    try {
        // if we are in the image browsing mode, viewing a medium-sized image,
        // this will find an element
        var m, img, video, a
        if (a = document.querySelector("#big_image a")) {
            if (m = a.href.match(/\/\d+[^\/]+$/)) {
                // fix the link to point directly to the image
                a.href = "//images.apina.biz/full" + m[0]
                // and remove that annoying title popup while we're at it
                a.removeAttribute("title")

                var parent = a.parentElement

                // change the img element to use the full-sized image and appear wider
                if (img = a.querySelector("img")) {
                    // we have to remove this image and create a new one,
                    // to prevent it from visibly growing moments later
                    a.removeChild(img)
                    img = new Image()
                    addZoomIndicator(img, parent, "load")
                    img.src = a.href
                    img.style.maxWidth = "100%"
                    a.appendChild(img)
                }
                else if (video = a.querySelector("video")) {
                    // webm/mp4 video instead?
                    // let it auto-size
                    video.removeAttribute("width")
                    video.removeAttribute("height")
                    video.style.maxWidth = "100%"

                    // to enable pausing and other controls, move it outside the <a>
                    parent.removeChild(a)

                    // we need a new <video> element, the old one's events may have fired
                    var newvideo = video.cloneNode(false)

                    // "canplay" seems to fire at a time when the video element size has settled
                    addZoomIndicator(newvideo, parent, "canplay")

                    // replace small sources with full-sized ones
                    for (var source of video.querySelectorAll("source")) {
                        var newsource = source.cloneNode(false)
                        newsource.src = source.src.replace(/medium\/m_/, "full/")
                        newvideo.appendChild(newsource)
                    }
                    parent.appendChild(newvideo)
                }
            }
        }

        // handle the randoms memory    
        if (m = location.href.match(/apina\.biz\/(\d+)$/)) {
            var pic = m[1]
            var randoms = document.getElementById("randoms")
            var stored = localStorage.getItem(pic)
            if (stored) {
                try {
                    stored = JSON.parse(stored)
                    randoms.innerHTML = stored.randoms
                    console.log("restored randoms from cache")
                }
                catch (e) { }
            }
            localStorage.setItem(pic, JSON.stringify({
                time: Date.now(),
                randoms: randoms.innerHTML
            }))
        }
    }
    finally {
        // re-enable displaying the picture and randoms bar
        head.removeChild(style)
    }

}, false)

// if it's been too long since the last cleanup of the randoms cache, do it now
var lastcleanup = parseInt(localStorage["lastcleanup"])
if (!lastcleanup || lastcleanup < Date.now() - 0.1*randoms_cache_ms) {
    localStorage["lastcleanup"] = Date.now()

    console.log("cleaning randoms cache")
    for (var key of Object.keys(localStorage)) {
        if (key.match(/^\d+$/)) {
            var keep = false
            try {
                var stored = JSON.parse(localStorage.getItem(key))
                if (stored.time > Date.now() - randoms_cache_ms) {
                    keep = true
                }
            }
            catch (e) { }

            if (!keep) {
                localStorage.removeItem(key)
                console.log("flushed " + key + " from localStorage")
            }
        }
    }

}