Board Game Geek - One page auction geeklists

Loads all geeklist items into a single view simmilar to Peyo61's external tool.

Versión del día 29/8/2022. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name         Board Game Geek - One page auction geeklists
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Loads all geeklist items into a single view simmilar to Peyo61's external tool.
// @author       Kempeth @ boardgamegeek
// @match        https://boardgamegeek.com/geeklist/*
// @icon         https://cf.geekdo-static.com/icons/favicon2.ico
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

const FETCHLIMIT = 10000;
var btnConvert;
var btnItems;
var progressFull;
var progressEmpty;
var geeklistid;
var itemList;
var firstItem;
var taggedItems = [];

(function() {
    'use strict';

    //console.log('root function');

    init();
})();

function retry(f)
{
    window.setTimeout(f, 500);
}

function init()
{
    //console.log('init function');

    var els = document.getElementsByTagName('gg-geeklist-page-ui');
    //console.log(els);
    if (els.length == 0) { retry(init); return; }

    els = els[0].getElementsByTagName('header');
    //console.log(els);
    if (els.length == 0) { retry(init); return; }

    els = els[0].getElementsByTagName('nav');
    //console.log(els);
    if (els.length == 0) { retry(init); return; }

    var el = els[0];
    btnConvert = document.createElement('button');
    btnConvert.innerHTML = "One Page Auction";
    btnConvert.className = "btn btn-warning";
    btnConvert.onclick = convert;
    el.append(btnConvert);
}

function setProgress(done, total)
{
    var percentage = done * 100.0 / total;
    progressFull.style.width = percentage + '%';
    progressEmpty.style.width = (100 - percentage) + '%';
    progressFull.setAttribute('aria-valuemax', total);
    progressFull.setAttribute('aria-valuenow', done);
    if (percentage > 50)
    {
        progressFull.innerHTML = done + ' / ' + total;
        progressEmpty.innerHTML = '';
    }
    else
    {
        progressEmpty.innerHTML = done + ' / ' + total;
        progressFull.innerHTML = '';
    }
}

function convert()
{
    var els = document.getElementsByTagName('gg-geeklist-page-ui');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }

    els = els[0].getElementsByTagName('div');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }

    var footerNav = els[0].getElementsByTagName('nav');
    //console.log(footerNav);
    if (els.length == 0) { retry(convert); return; }
    footerNav = footerNav[footerNav.length - 1];

    els = els[0].getElementsByTagName('header');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }

    els = els[0].getElementsByTagName('nav');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }
    var headerNav = els[0];

    els = document.getElementsByTagName('gg-geeklist-items-ui');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }

    els = els[0].getElementsByTagName('div');
    //console.log(els);
    if (els.length == 0) { retry(convert); return; }
    itemList = els[0];

    // remove header items
    for (var child of headerNav.childNodes)
    {
        if (child.tagName != 'GG-THUMBS-GEEKGOLD-GIVEN' && child.tagName != 'GG-SUBSCRIPTION-BUTTON')
        {
            headerNav.removeChild(child);
        }
    }

    // add header items
    var progress = document.createElement('div');
    progress.className = "progress";
    progress.style.height = "32px";
    progress.style.width = "256px";
    headerNav.appendChild(progress);

    progressFull = document.createElement('div');
    progressFull.className = "progress-bar";
    progressFull.setAttribute('role', 'progressbar');
    progressFull.setAttribute('aria-valuemin', 0);
    progressFull.setAttribute('aria-valuemax', 0);
    progressFull.setAttribute('aria-valuenow', 0);
    progressFull.style.width = '0%';
    progressFull.innerHTML = '';
    progress.appendChild(progressFull);

    progressEmpty = document.createElement('div');
    progressEmpty.className = "progress-bar bg-secondary";
    progressEmpty.setAttribute('role', 'progressbar');
    progressEmpty.style.width = '100%';
    progressEmpty.innerHTML = '0 / ???';
    progress.appendChild(progressEmpty);

    var btn = document.createElement('button');
    btn.innerHTML = "Refresh";
    btn.className = "btn btn-primary";
    headerNav.appendChild(btn);

    // remove convert button
    btnConvert.parentNode.removeChild(btnConvert);

    // remove geeklist items
    //itemList.innerHTML = '';

    firstItem = itemList.childNodes[0];
    itemList.className = "tw-grid tw-gap-2";

    // remove footer nav
    //footerNav.parentNode.removeChild(footerNav);
    footerNav.innerHTML = '';

    geeklistid = window.location.pathname.split('/')[2];

    getTaggedItems();
    fetchPage(1);
}

function fetchPage(page)
{
    // https://api.geekdo.com/api/listitems?page=1&listid=301669
    var url = "https://api.geekdo.com/api/listitems?page=" + page + "&listid=" + geeklistid;

    fetch(url)
        .then(response => response.json())
        .then(
        data => {
            //console.log(data);

            var nr = (data.pagination.pageid - 1) * data.pagination.perPage;
            for (var item of data.data)
            {
                nr++;
                makeRow(nr, item);
            }
            setProgress(nr, data.pagination.total);

            if (data.data.length < data.pagination.perPage)
            {
                console.log("last page");
            }
            else if (page < FETCHLIMIT)
            {
                console.log("more pages");
                fetchPage(page + 1);
            }
        }
    );
}

function makeRow(nr, item)
{
    var row = document.createElement('span');
    row.className = "tw-relative tw-flex tw-flex-wrap tw-items-center tw-gap-x-1.5 tw-gap-y-2 tw-rounded-md tw-border tw-border-gray-400 tw-bg-gray-100 tw-p-2";
    const thingtype = item.item.href.split('/')[1];
    const bodylower = item.body.toLowerCase();
    const notsold = bodylower.includes("not sold");
    const soldto = bodylower.includes("sold to");
    const sold = bodylower.includes("sold");
    const auctionclosed = bodylower.includes("auction closed");

    var struckout = 0;
    var struckoutstart = bodylower.indexOf("[-]");
    var struckoutend = bodylower.indexOf("[/-]");
    while (struckoutstart >= 0 && struckoutend >= 0)
    {
        struckout += struckoutend - struckoutstart;
        struckoutstart = bodylower.indexOf("[-]", struckoutstart + 1);
        struckoutend = bodylower.indexOf("[/-]", struckoutend + 1);
    }


    var tagButton = document.createElement("button");
    if (taggedItems.includes(item.id))
    {
        tagButton.className = "btn btn-sm btn-primary";
        tagButton.innerText = "Tagged";
    }
    else
    {
        tagButton.className = "btn btn-sm btn-outline-primary";
        tagButton.innerText = "Tag";
    }
    tagButton.onclick = () => {
        toggleTaggedItem(tagButton, item.id);
    };
    row.appendChild(tagButton);

    var tagGeeklistLink = document.createElement("a");
    tagGeeklistLink.href = "/geeklist/" + geeklistid + "/test?itemid=" + item.id + "#" + item.id;
    tagGeeklistLink.target = "_blank";
    tagGeeklistLink.innerText = nr + ".";
    row.appendChild(tagGeeklistLink);

    var txtThingType = document.createTextNode(thingtype == "boardgame" ? "Boardgame" : thingtype == "boardgameexpansion" ? "Expansion" : "Other");
    row.appendChild(txtThingType);

    var tagGeeklistItemLink = document.createElement("a");
    tagGeeklistItemLink.href = item.item.href;
    tagGeeklistItemLink.target = "_blank";
    tagGeeklistItemLink.style.maxWidth = "50%";
    tagGeeklistItemLink.style.textOverflow = "ellipsis";
    tagGeeklistItemLink.style.overflow = "hidden";
    tagGeeklistItemLink.style.whiteSpace = "nowrap";
    tagGeeklistItemLink.innerText = encodeWithTextNode(item.item.name)
    row.appendChild(tagGeeklistItemLink);

    var tagState = document.createElement("span");
    if (notsold)
    {
        tagState.innerText = "not sold";
        tagState.className = "badge bg-danger";
    }
    else if (soldto || sold)
    {
        tagState.innerText = "sold";
        tagState.className = "badge bg-danger";
    }
    else if (auctionclosed || struckout > 100)
    {
        tagState.innerText = "closed";
        tagState.className = "badge bg-secondary";
    }
    else
    {
        tagState.innerText = "open";
        tagState.className = "badge bg-success";
    }
    row.appendChild(tagState);

    itemList.insertBefore(row, firstItem);
}

function encodeWithTextNode(htmlstring) {
	let textarea = document.createElement('textarea');
	let text = document.createTextNode(htmlstring);
	textarea.appendChild(text);
	return textarea.innerHTML;
}

function getTaggedItems()
{
    //GM_setValue("GamePage_PlayTime_" + gameid, JSON.stringify(cached));
    //var cached = JSON.parse(GM_getValue("GamePage_PlayTime_" + gameid, "{}"));
    taggedItems = JSON.parse(GM_getValue("TaggedItems_" + geeklistid, "[]"));
}

function toggleTaggedItem(btn, itemid)
{
    if (taggedItems.includes(itemid))
    {
        taggedItems = taggedItems.filter(i => i != itemid);
        btn.className = "btn btn-sm btn-outline-primary";
        btn.innerText = "Tag";
    }
    else
    {
        taggedItems[taggedItems.length] = itemid;
        btn.className = "btn btn-sm btn-primary";
        btn.innerText = "Tagged";
    }
    GM_setValue("TaggedItems_" + geeklistid, JSON.stringify(taggedItems));
}