Backloggery-Exporter

Export game data from Backloggery

// ==UserScript==
// @name         Backloggery-Exporter
// @namespace    https://backloggery.com/
// @version      1.2
// @description  Export game data from Backloggery
// @author       xdpirate
// @license      GPLv3
// @match        https://backloggery.com/games.php?user=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=backloggery.com
// @grant        none
// ==/UserScript==

function exportGames(exportType) {
    let gameElements = document.querySelectorAll("section.gamebox");
    let games = [];

    for(let i = 0; i < gameElements.length; i++) {
        if(!gameElements[i].classList.contains("systemend")) {
            let game = {};

            // game.name - Name of the game
            game.name = gameElements[i].querySelector("h2 > b").innerText;

            if(!game.name.includes("▲")) { // Skip if it's a compilation box without a game attached
                // game.compilation - Game compilation
                if(gameElements[i].parentNode.id.startsWith("comp")) {
                    game.compilation = gameElements[i].parentNode.closest("section.gamebox").querySelector("h2 > b").innerText.replace("▲","").trim();
                } else if(gameElements[i].querySelector("h2 > b + span[id^=arrow]")) {
                    game.compilation = game.name;
                } else {
                    game.compilation = "undefined";
                }

                // game.system - Platform/game console the game is on
                game.system = gameElements[i].querySelector("div.gamerow > b").innerText;
                
                // game.originalSystem - Platform/console the game originally appeared on
                if(game.system.includes("(")) {
                    game.originalSystem = game.system.match(/\((.+)\)/)[1];
                    game.system = game.system.match(/(.+) \(.+/)[1];
                } else {
                    game.originalSystem = "undefined";
                }
                
                // game.region - The game's region
                if(gameElements[i].querySelector("h2 > b + img[class=lift]")) {
                    game.region = gameElements[i].querySelector("h2 > b + img[class=lift]").title;
                } else {
                    game.region = "default";
                }

                // game.ownership - Ownership status of the game
                let ownershipElem = gameElements[i].querySelector("div.gamerow > img[src*=own_]");
                if(ownershipElem) {
                    if(ownershipElem.src.includes("own_other.gif")) {
                        game.ownership = "Other";
                    } else {
                        game.ownership = gameElements[i].querySelector("div.gamerow > img[src*=own_]").title;
                    }
                } else {
                    game.ownership = "Owned";
                }

                // game.status - Completion status of the game
                let status = gameElements[i].querySelector(`h2 > a[href*="games.php"] > img`).alt;
                if(status == "(-)") {
                    game.status = "Null";
                } else if(status == "(C)") {
                    game.status = "Completed";
                } else if(status == "(B)") {
                    game.status = "Beaten";
                } else if(status == "(U)") {
                    game.status = "Unfinished";
                } else if(status == "(M)") {
                    game.status = "Mastered";
                } else if(status == "(u)") {
                    game.status = "Unplayed";
                }

                // game.achievementsEarned - Achievements earned
                // game.achievementsTotal - Achievements total
                let achiElement = gameElements[i].querySelector("div.gamerow > span.info > img[src*=ribbon]");
                if(achiElement) {
                    game.achievementsEarned = achiElement.nextElementSibling.innerText.match(/Achievements: ([0-9]+) \/ [0-9]+/)[1];
                    game.achievementsTotal = achiElement.nextElementSibling.innerText.match(/Achievements: [0-9]+ \/ ([0-9]+)/)[1];
                } else {
                    game.achievementsEarned = "undefined";
                    game.achievementsTotal = "undefined";
                }

                // game.onlineInfo - Online info for the game
                let onlineElem = gameElements[i].querySelector("div.gamerow > span.info > img[src*=online_info]");
                if(onlineElem) {
                    game.onlineInfo = onlineElem.nextElementSibling.innerText;
                } else {
                    game.onlineInfo = "undefined";
                }

                // game.progressNote - Progress note string for the game
                let progNoteElem = gameElements[i].querySelector("div.gamerow:nth-of-type(2)");
                if(progNoteElem) {
                    game.progressNote = progNoteElem.innerText;
                } else {
                    game.progressNote = "undefined";
                }

                // game.rating - Star rating of the game on a 5-point scale
                let ratingElem = gameElements[i].querySelector("div.gamerow > img.lift[src*=stars]");
                if(ratingElem) {
                    if(ratingElem.src.includes("1_5stars.gif")) {
                        game.rating = "1";
                    } else if(ratingElem.src.includes("2_5stars.gif")) {
                        game.rating = "2";
                    } else if(ratingElem.src.includes("3_5stars.gif")) {
                        game.rating = "3";
                    } else if(ratingElem.src.includes("4_5stars.gif")) {
                        game.rating = "4";
                    } else if(ratingElem.src.includes("5_5stars.gif")) {
                        game.rating = "5";
                    }
                } else {
                    game.rating = "undefined";
                }

                // game.comments - Extended comments on a game
                let commentsElem = gameElements[i].querySelector("div.gamerow[id^=comments]");
                if(commentsElem) {
                    game.comments = commentsElem.innerText;
                } else {
                    game.comments = "undefined";
                }

                // game.nowPlaying - Whether the game is marked as now playing
                if(gameElements[i].classList.contains("nowplaying")) {
                    game.nowPlaying = true;
                } else {
                    game.nowPlaying = false;
                }

                console.log(game);
                games.push(game);
            }
        }
    }

    let element = document.createElement('a');
    if(exportType == "json") {
        element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(games)));
    } else if(exportType == "csv") {
        element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSONtoCSV(games)));
    }

    element.setAttribute("download", `${GM_info.script.name}-${Date.now()}.${exportType}`);
    element.style.display = "none";
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
}

function JSONtoCSV(jsonData) {
    const jsonKeys = [];
    for (const key in jsonData[0]) {
        jsonKeys.push(key);
    }
    var json2CSV = jsonKeys.join(',') + '\n';

    for (var i = 0; i < jsonData.length; i++) {
        var row = '';
        for(const key of jsonKeys) {
            if (row !== '') {
                row += ',';
            }
            row += "\"" + String(jsonData[i][key]).replaceAll("\"","\"\"") + "\"";
        }
        json2CSV += row + '\n';
    }

    return json2CSV;
}

async function expandComps() {
    let openers = document.querySelectorAll("span.lessmore");

    for(let i = 0; i < openers.length; i++) { 
        openers[i].click();
        let percentage = Math.floor(((i+1)/openers.length)*100);
        document.querySelector("#spanProgress").innerText = `${percentage}% (${i+1}/${openers.length})`;
        document.querySelector("#progbar").value = percentage;
        await new Promise(r => setTimeout(r, 500));
    }

    document.querySelector("#loadingBar").style.display = "none";
    document.querySelector("#divExportBtns").style.display = "block";
}

window.setTimeout(function() {
    let exporterDiv = document.createElement("div");
    exporterDiv.innerHTML = `
        <div style="border: 1px solid; border-radius: 10px; padding: 10px; margin: 10px;">
            <b>Backloggery Exporter</b><br />
            <div id="divExportBtns" style="display: none;">
                <input type="button" value="Export as JSON" id="btnExportJSON" name="btnExportJSON" /> 
                <input type="button" value="Export as CSV" id="btnExportCSV" name="btnExportCSV" />
            </div>
            <div id="loadingBar">
                Expanding compilations, please wait...<br />
                <span id="spanProgress">0%</span><br />
                <progress id="progbar" max="100">
            </div>
        </div>
    `;
    document.querySelector("#intro").insertAdjacentElement("beforeend", exporterDiv);

    document.querySelector("#btnExportJSON").onclick = function() {
        exportGames("json");
    };
    
    document.querySelector("#btnExportCSV").onclick = function() {
        exportGames("csv");
    };

    expandComps();
}, 1500);