Barter.vg, Thumbnail

always display thumbnail of game

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Barter.vg, Thumbnail
// @namespace    http://tampermonkey.net/
// @version      0.5.11
// @description  always display thumbnail of game
// @icon         https://www.google.com/s2/favicons?sz=64&domain=barter.vg
// @author       You
// @match        https://barter.vg/*
// @match        https://bartervg.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==
(function() {
    const STORAGE_KEY = "BarterToSteamThumbnailMaps";
    const pages = {
        bundles : location.pathname.indexOf("/bundles/") == 0,
        bundle: location.pathname.indexOf("/bundle/") == 0,
        giveways: location.pathname.indexOf("/giveways/") == 0,
        browse: location.pathname.indexOf("/browse/") == 0,
        wishlist: location.pathname.indexOf("/w/") > 0,
        tradable: location.pathname.indexOf("/t/") > 0,
        blacklist: location.pathname.indexOf("/b/") > 0,
        scrachpad: location.pathname.indexOf("/c/") > 0,
        library: location.pathname.indexOf("/l/") > 0,
        offer: location.pathname.indexOf("/o/") > 0,
        info: location.pathname.indexOf("/i/") == 0,
        traded: location.pathname.indexOf("/d/") > 0,
        fulfilled: location.pathname.indexOf("/f/") > 0,
        matching: location.pathname.indexOf("/m/") > 0,
        editing: location.pathname.indexOf("/e/") > 0,
        revoked: location.pathname.indexOf("/v/") > 0,
    };

    console.log("[bt] page info", pages);

    const lazyLoading = [];
    const thumbnailsMap = restoreThumbnailMap();
    const sidRegex = /(app|sub)\/\d+/g;

    function restoreThumbnailMap() {
        try {
            var map = JSON.parse(localStorage[STORAGE_KEY]);
        } finally {
            return typeof map == "object" ? map : {};
        }
    }

    function saveThumbnailMap() {
        localStorage[STORAGE_KEY] = JSON.stringify(thumbnailsMap);
    }

    function makeThumbUrl(id) {
        return `https://steamcdn-a.akamaihd.net/steam/${id.replace("/", "s/")}/capsule_184x69.jpg`;
    }

    function makeHeaderUrl(id) {
        return `https://steamcdn-a.akamaihd.net/steam/${id.replace("/", "s/")}/header.jpg`;
    }

    // bid : Barter ID
    // sid : Steam Store ID (sub/app)
    function bidToSid(bid) {
        var sid = thumbnailsMap[bid];
        if (!sid) return;

        if (sid.indexOf("/i/") == 0) {
            sid = thumbnailsMap[sid.replace("/i/", "")];
        }
        return sid;
    }

    function applyToMatching(barter) {
        var bid = barter.href.match(/\d+/g)[0];
        var sid = bidToSid(bid);
        if (!sid) return;

        var li = barter.closest("li");
        li.setAttribute("thumbnail", "");
        lazyLoading.push({
            element: li,
            backgroundImage: `url('${makeThumbUrl(sid)}'), url('${makeHeaderUrl(sid)}'), var(--unknown-thumbnail)`,
            rect: li.getBoundingClientRect()
        });
    }

    function applyToCollection(barter) {
        if (barter.href.indexOf("#") >= 0) return;
        var bid = barter.href.match(/\d+/g)[0];

        var tr = barter.closest("tr");
        if (!tr) return;
        var td = barter.closest("td");
        if (!td) return;

        var sid = bidToSid(bid),
            steam = tr.querySelector("a[href*='/app/'], a[href*='/sub/']"),
            isSub = steam && steam.href.indexOf("/sub/") >= 0;
        if (steam) {
            if (!isSub || !sid) {
                sid = steam.href.match(sidRegex)[0];
                thumbnailsMap[bid] = sid;

                /// console.log(`[bt] saved /i/${bid} to ${sid} (${barter.innerText})`);
            }
        }

        var background = sid ? `url('${makeThumbUrl(sid)}'), url('${makeHeaderUrl(sid)}'), var(--unknown-thumbnail)` : `var(--unknown-thumbnail)`;
        var nid;
        if (isSub && tr.classList.contains("included")) {
            var next = tr.nextSibling;
            if (next) {
                var baseSteam = next.querySelector("[href*='/sub/'], [href*='/app/']"), baseBarter = next.querySelector("[href*='/i/']");
                if (baseSteam) {
                    nid = baseSteam.href.match(sidRegex)[0];
                    thumbnailsMap[bid] = nid;

                    // console.log(`[bt] base game is ${nid}`);
                } else if (baseBarter) {
                    nid = bidToSid(baseBarter.href.match(/\d+/g)[0]);
                }

                if (nid) {
                    background = `url('${makeThumbUrl(nid)}'), url('${makeHeaderUrl(nid)}'), ${background}`;
                }
            }
        }

        if (isSub || sid || nid) {
            td.setAttribute("thumbnail", "");
            lazyLoading.push({
                element: td,
                backgroundImage: background,
                rect: td.getBoundingClientRect()
            });
        }
    }

    function applyToOffer(barter) {
        if (barter.href.indexOf("#") >= 0) return;
        var bid = barter.href.match(/\d+/g)[0];

        var tr = barter.closest("tr");
        if (!tr) return;
        var td = barter.closest("td");
        if (!td) return;

        var sid = bidToSid(bid),
            steam = tr.querySelector("a[href*='/app/'], a[href*='/sub/']"),
            isSub = steam && steam.href.indexOf("/sub/") >= 0;
        if (steam) {
            if (!isSub || !sid) {
                sid = steam.href.match(sidRegex)[0];
                thumbnailsMap[bid] = sid;

                /// console.log(`[bt] saved /i/${bid} to ${sid} (${barter.innerText})`);
            }
        }

        var background = sid ? `url('${makeThumbUrl(sid)}'), url('${makeHeaderUrl(sid)}'), var(--unknown-thumbnail)` : `var(--unknown-thumbnail)`;
        var nid;
        if (isSub && tr.classList.contains("included")) {
            var next = tr.nextSibling;
            if (next) {
                var baseSteam = next.querySelector("[href*='/sub/'], [href*='/app/']"), baseBarter = next.querySelector("[href*='/i/']");
                if (baseSteam) {
                    nid = baseSteam.href.match(sidRegex)[0];
                    thumbnailsMap[bid] = nid;

                    // console.log(`[bt] base game is ${nid}`);
                } else if (baseBarter) {
                    nid = bidToSid(baseBarter.href.match(/\d+/g)[0]);
                }

                if (nid) {
                    background = `url('${makeThumbUrl(nid)}'), url('${makeHeaderUrl(nid)}'), ${background}`;
                }
            }
        }

        if (sid || nid) {
            td.setAttribute("thumbnail", "");
            lazyLoading.push({
                element: td,
                backgroundImage: background,
                parent: barter.closest("div"),
            });
        }
    }

    var scrollTimer = 0;
    function onScroll(ev) {
        if (scrollTimer > 0) return;

        scrollTimer = setTimeout(function () {
            var item, scrollTop, clientHeight, itemTop, preloadingMargin;

            for (var i = 0; i < lazyLoading.length; i++) {
                item = lazyLoading[i];

                if (pages.offer) {
                    if (ev.target != item.parent) continue;
                    scrollTop = ev.target.getBoundingClientRect().top;
                    clientHeight = ev.target.clientHeight;
                    itemTop = item.element.getBoundingClientRect().top;
                    preloadingMargin = 100;
                } else {
                    scrollTop = 0;
                    clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
                    itemTop = item.element.getBoundingClientRect().top;
                    preloadingMargin = 500;
                }

                if (scrollTop - preloadingMargin < itemTop && itemTop < scrollTop + clientHeight + preloadingMargin) {
                //if (itemTop < scrollTop + preloadingMargin) {
                    item.element.style.setProperty("--thumbnail", item.backgroundImage);
                    // console.log(item.element.parentNode.innerText, scrollTop, clientHeight, itemTop);
                    lazyLoading.splice(i, 1);
                    i--;
                }
            }
            scrollTimer = 0;
        }, 50);
    }

    function onMatchingPage() {
        var items = document.querySelectorAll(`.matchcol a[href*='/i/']`);
        for (var i = 0; i < items.length; i++) {
            applyToMatching(items[i]);
        }
    }

    function onCollectionPage() {
        var items = document.querySelectorAll(`.collection tr a[href*='/i/']`);
        for (var i = 0; i < items.length; i++) {
            applyToCollection(items[i])
        }
    }

    function onOfferPage() {
        var items = document.querySelectorAll(`.collection tr a[href*='/i/']`);
        for (var i = 0; i < items.length; i++) {
            applyToOffer(items[i]);
        }
    }

    function compareNumbers(a, b) {
        return a - b;
    }

    function fetchBaseGame() {
        var tags = document.querySelectorAll(".tag");
        if (tags.length == 0) return;

        tags = Array.prototype.filter.call(tags, t => t.innerText.trim() == "included");
        tags = Array.prototype.map.call(tags, t => {
            var b = t.closest("li").querySelector("a[href*='/i/']");
            return parseInt(b.href.match(/\d+/g)[0]);
        });
        Array.prototype.sort.call(tags, compareNumbers);
        return tags[0];
    }

    function onInfoPage() {
        // save thumbnail map
        var sid, bid = location.pathname.match(/\d+/)[0];
        var steamHeader = document.querySelector(`#main > a[href*='/sub/'] img, #main > a[href*='/app/'] img`);
        var isSub = steamHeader && steamHeader.src.indexOf("/subs/") >= 0;

        if (steamHeader) {
            if (isSub) {
                var baseBid = fetchBaseGame();
                if (baseBid) {
                    thumbnailsMap[bid] = `/i/${baseBid}`;

                    console.log(`[bt] saved ${bid} to ${thumbnailsMap[bid]}`);
                }

                sid = bidToSid(bid);
                if (sid) {
                    steamHeader.src = makeHeaderUrl(sid);

                    console.log("[bt] header image was replaced");
                }
            } else {
                var steam = steamHeader.closest("a");
                sid = steam.href.match(sidRegex)[0];
                thumbnailsMap[bid] = sid;

                console.log(`[bt] saved /i/${bid} to ${sid}`);
            }

        } else {
            var steamVersion = document.querySelector("#bc a[href*='/i/']:has(img[src*='steam.png'])");
            if (!steamVersion) return;
            thumbnailsMap[bid] = `/i/${steamVersion.href.match(/\d+/g)[0]}`;

            console.log(`[bt] saved /i/${bid} to ${thumbnailsMap[bid]}`);
        }
    }

    function delay(ts) {
        return new Promise((callback) => {
            setTimeout(callback, ts);
        });
    }

    function onLoaded () {
        // console.log("items", items);

        if (pages.info) {
            onInfoPage();
        } else if (pages.offer) {
            onOfferPage();
        } else if (pages.matching) {
            onMatchingPage();
        } else if (pages.bundle) {
            // do noting
        } else {
            onCollectionPage();
        }

        // console.log("lazyLoading", lazyLoading);

        saveThumbnailMap();

        if (pages.offer) {
            document.querySelectorAll(".collectionSelect").forEach(async function (el) {
                await delay(100);
                el.addEventListener("scroll", onScroll);
                onScroll.call(el, { target: el });
            });
        } else {
            window.addEventListener("scroll", onScroll);
            window.dispatchEvent(new Event("scroll"));
        }

        var style = document.createElement("style");
        style.innerHTML = `
body {
    --unknown-thumbnail: url('https://bartervg.com/imgs/ico/steam184_69.png');
}
.matchcol [thumbnail] {
    position: relative;
}
.matchcol [thumbnail]:before {
    display: inline-block;
    position: absolute;
    content: "";
    width: 184px;
    min-height: 30px;
    right: 0;
    pointer-events: none;
    opacity: 0.5;
    z-index: -1;
    background-image: var(--thumbnail);
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
}

.collection td { vertical-align: middle; padding-top: 0; padding-bottom: 0; }
.collection td abbr + div { display: inline-block; }
.collection [thumbnail]:before {
    display: inline-block;
    position: relative;
    content: "";
    margin-right: 8px;
    width: 184px;
    min-height: 30px;
    vertical-align: middle;
    background-image: var(--thumbnail);
    background-repeat: no-repeat;
    background-position: center;
    background-size: cover;
}

.showMoreTable tr.included td[thumbnail] { padding-left: 8px; }

#listEdit { z-index: 100; }
`;
        document.querySelector("head").appendChild(style);
    }
    onLoaded();
})();