IGDB List Extra Info

Adds additional information (genre, rating, keywords)to igdb.com lists. They can be loaded witha button // click. Needs an IGDB api key.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         IGDB List Extra Info
// @namespace    https://greasyfork.org/de/users/155913-nkay08
// @description  Adds additional information  (genre, rating, keywords)to igdb.com lists. They can be loaded witha button // click. Needs an IGDB api key.
//
// @author       NKay
// @include        http*://www.igdb.com/*
// @grant        none
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @version 0.0.3.201808121415
// ==/UserScript==


//insert your API-KEY here
var apikey = '';


var apiurl;
var req;
var reqid;
var corsproxy;
var fields;
var fieldsall


var myheaders;

var gametextarray;
var gameidarray;
var genresnodearray;
var keywordsnodearray;
var ratingnodearray;
var ttbnodearray;

var keyword_dict = {};
var genres_dict = {};
var id_list = {};
var genres_list_list = {};
var genres_list = {};
var keyword_list = {};
var games_info = {};
var games_text_info = {};

var idortext;

var keyelement = "div.content-left.col-md-pull-10.col-md-2";
//only execute function if this element is loaded via ajax
waitForKeyElements(keyelement, checkForElement);

//waitForKeyElements(keyelement,alert1);

function alert1() {
    alert('alert');
}

function init() {
    apiurl = 'https://api-endpoint.igdb.com';
    req = '/games/?search=';
    reqid = '/games/1942?fields=*';
    corsproxy = 'https://cors-anywhere.herokuapp.com/';
    fields = '?fields=genres,keywords,rating,rating_count,aggregated_rating,aggregated_rating_count,total_rating,total_rating_count,time_to_beat';
    fieldsall = 'fields=*';
    myheaders = new Headers();
    myheaders.append('user-key', apikey);
    myheaders.append('Accept', 'application/json');
    gametextarray = [];
    gameidarray = [];
    genresnodearray = [];
    keywordsnodearray = [];
    ratingnodearray = [];
    ttbnodearray = [];

    reset_data();

    idortext = 'text';

    /*var fe = fetch('https://cors-anywhere.herokuapp.com/https://api-endpoint.igdb.com/games/?search=Halo&fields=*', {headers: myheaders})
    .then(res2 => res2.json())
    .then(data => console.log("halo",data))
    .catch(function (err) {
        console.log(err.message);
        console.log(err.stack);
    })
    .catch(function (err) {
        console.log(err.message);
        console.log(err.stack);
    });*/


}

function checkForElement(jnode) {
    if (!document.getElementById('btnaddinfo')) {
        init();
        addButton();
        addAdditionalInfo();
    }
}

function populateGametextarray(element) {
    //get the game name
    //console.log(element);
    var gameurlelement = element.getElementsByTagName('a');
    var gameurl = gameurlelement[0].getAttribute("href");
    var found = gameurl.match(/[A-Za-z0-9_\-]*$/);
    var textfromurl = found[0].replace(/-/g, " ");
    var span1 = element.getElementsByTagName('span');
    var gametext = span1[0].innerHTML;
    var cururl = corsproxy + apiurl + req + gametext;
    gametextarray.push(gametext);
    //console.log(textfromurl);
    //gametextarray.push(cururl);
    //console.log(cururl)

}

function populateGameidarray(element) {
    // get sibling. sibling has game id
    var sib = element.nextSibling;
    var gameid = sib.getAttribute("data-game");
}

function addTextNodes(div) {
    for (var i = 0; i < div.length; i++) {
        //     console.log(div[i]);
        addTextNode(div[i], i);
    }
}

function addTextNode(el, i) {
    var genrestext = document.createTextNode('Genres: ');
    var genresspan = document.createElement('span');
    genresspan.style.fontSize = 'medium';
    genresspan.style.textDecoration = 'underline';
    genresspan.appendChild(genrestext);
    el.appendChild(genresspan);
    var genresnode = document.createElement('span');
    genresnode.setAttribute("id", "usgenre" + i.toString());
    el.appendChild(genresnode);
    genresnodearray.push(genresnode);
    el.appendChild(document.createTextNode('   |   '));
    var keywordstext = document.createTextNode('Keywords: ');
    var kwspan = document.createElement('span');
    kwspan.style.fontSize = 'medium';
    kwspan.style.textDecoration = "underline";
    kwspan.appendChild(keywordstext);
    el.appendChild(kwspan);
    var keywordsnode = document.createElement('span');
    keywordsnode.setAttribute("id", "uskw" + i.toString());
    el.appendChild(keywordsnode);
    keywordsnodearray.push(keywordsnode);
    el.appendChild(document.createTextNode('   |   '));
    var ratingtext = document.createTextNode('Rating: ');
    var rtspan = document.createElement('span');
    rtspan.style.fontSize = 'medium';
    rtspan.style.textDecoration = "underline";
    rtspan.appendChild(ratingtext);
    el.appendChild(rtspan);
    var ratingnode = document.createTextNode('');
    el.appendChild(ratingnode);
    ratingnodearray.push(ratingnode);
    el.appendChild(document.createTextNode('   |   '));
    var ttbtext = document.createTextNode('TTB: ');
    var ttbspan = document.createElement('span');
    ttbspan.style.fontSize = 'medium';
    ttbspan.style.textDecoration = 'underline';
    ttbspan.appendChild(ttbtext);
    var ttbnode = document.createElement('span');
    el.appendChild(ttbspan);
    el.appendChild(ttbnode);
    ttbnodearray.push(ttbnode);

    if (idortext == 'text') {
        populateGametextarray(el);
    }
    if (idortext == 'id') {
        populateGameidarray(el);
    }


}


function addButton() {
    //add Button
    var btn = document.createElement("button");
    var btntext = document.createTextNode('Load info (less hits)');
    btn.appendChild(btntext);
    btn.addEventListener("click", function () {
        load(idortext);
    }, false);
    btn.setAttribute("id", "btnaddinfo");
    var btn2 = document.createElement("button");
    var btntext2 = document.createTextNode('Load genres (more hits)');
    btn2.appendChild(btntext2);
    btn2.addEventListener("click", function () {
        loadgenres(idortext);
    }, false);
    btn2.setAttribute("id", "btnaddinfo2");
    var btn3 = document.createElement("button");
    var btntext3 = document.createTextNode('Load keywords (more hits)');
    btn3.appendChild(btntext3);
    btn3.addEventListener("click", function () {
        loadkws(idortext);
    }, false);
    btn3.setAttribute("id", "btnaddinfo3");
    var sidebar = document.getElementsByClassName("user-details-sidebar");
    if (sidebar) {
        var sibling = sidebar[0].nextSibling;

        sibling.parentNode.insertBefore(btn, sibling);
        sibling.parentNode.insertBefore(btn2, sibling);
        sibling.parentNode.insertBefore(btn3, sibling);
        sibling.parentNode.insertBefore(document.createElement("hr"), sibling);
    }

    function load(str) {
        loadbytext4(gametextarray, 1, 1, 0, 0, 0);
    }

    function loadgenres(str) {
        loadbytext4(gametextarray, 0, 0, 1, 0, 0);
    }

    function loadkws(str) {
        loadbytext4(gametextarray, 0, 0, 0, 1, 0);
    }

    //    var firstbtn = document.getElementsByClassName("panel-title");
    //    firstbtn[0].parentNode.insertBefore(document.createElement('hr'), firstbtn[0]);
    //    firstbtn[0].parentNode.insertBefore(btn, firstbtn[0]);
    //   firstbtn[0].parentNode.insertBefore(document.createElement('hr'), firstbtn[0]);
}

function addAdditionalInfo(jnode) {
    console.log('Adding button and placeholders for extra info');
    //	var pageDivs = document.getElementsByClassName("media-body");
    //	addTextNodes(pageDivs);

    var selector = "#content-page > div > div.content-left.col-md-push-2.col-md-10 > div:nth-child(2) > div.panel-body.listentries > div > div:nth-child(n) > div.media-body";
    var selector2 = "#content-page > div > div.content-left.col-md-push-2.col-md-10 > div > div.panel-body.listentries > div > div:nth-child(5) > div";
    var selectorgen = "div.listentries div.media div.media-body";
    var queryres = document.querySelectorAll(selectorgen);
    addTextNodes(queryres);
    // console.log(queryres);

}

function removeChildren(element) {
    while (element.firstChild) {
        element.removeChild(element.firstChild);
    }
}

async function loadbytext4(textarray, r = 0, ttb = 0, g = 0, k = 0, reset = 0) {
    console.log("Try loading data");
    if (reset != 0) {
        reset_data();
    } else {

        if (r != 0) {
            ratingnodearray.forEach(element => element.nodeValue = 'loading..');
        }
        if (g != 0) {
            genresnodearray.forEach(element => element.innerHTML = 'loading..');
        }
        if (k != 0) {
            keywordsnodearray.forEach(element => element.innerHTML = 'loading..');
        }
        if (ttb != 0) {
            //console.log(ttbnodearray);
            ttbnodearray.forEach(element => element.innerHTML = 'loading..');
        }
        if (r != 0 || g != 0 || k != 0) {
            console.log("games_text_info", Object.keys(games_text_info).length, ", gametextarray", gametextarray.length);
            if (Object.keys(games_text_info).length == gametextarray.length) {
                console.log("processing data cached");
                if (r != 0) {
                    gather_ratings();
                }
                if (g != 0) {
                    gather_genres();
                }
                if (k != 0) {
                    gather_kws();
                }
                if (ttb != 0) {
                    gather_ttb();
                }
            } else {
                reset_data();
                var gamespromise = gather_games_text_info(textarray);
                gamespromise
                    .then(function (result) {
                        console.log("processing data");
                        //console.log("gg",games_text_info);
                        if (r != 0) {
                            gather_ratings();
                        }
                        if (g != 0) {
                            gather_genres();
                        }
                        if (k != 0) {
                            gather_kws();
                        }
                        if (ttb != 0) {
                            gather_ttb();
                        }
                    })
                    .then(function () {
                        //console.log("2. ", "id_list", Object.keys(id_list).length, ", games_info", Object.keys(games_info).length, ", gametextarray", gametextarray.length);
                    })
                    .catch(function (err) {
                        console.log(err.message);
                        console.log(err.stack);
                    });
            }


        }

    }


}

function reset_data() {

    keyword_dict = {};
    genres_dict = {};
    id_list = {};
    genres_list_list = {};
    genres_list = {};
    keyword_list = {};
    games_info = {};
    games_text_info = {};

}

function gather_ttb() {
    console.log("gather ttb");
    ttbnodearray.forEach(function (element, index) {
        //var curr_id = id_list[gametextarray[index]];
        var curr_text = gametextarray[index];
        //console.log(curr_id);
        var game_info = games_text_info[curr_text];
        //console.log(game_info);
        removeChildren(element);
        if (game_info.time_to_beat) {
            var ttb = game_info.time_to_beat;
            var ttbstr = "";
            if (ttb.hastly) {
                ttbstr += +(ttb.hastly / 3600).toFixed(2) + "(h), ";
            }
            if (ttb.normally) {
                ttbstr += +(ttb.normally / 3600).toFixed(2) + "(n), ";
            }
            if (ttb.completely) {
                ttbstr += (ttb.completely / 3600).toFixed(2) + "(c)";
            }

            element.appendChild(document.createTextNode(ttbstr));
            //console.log("ttb", game_info.time_to_beat);
        } else {
            element.appendChild(document.createTextNode('n/a'));
        }
    });
}

function gather_ratings() {
    console.log("gather ratings");
    ratingnodearray.forEach(function (element, index) {
        //console.log("ratingelement",element, index);
        //var curr_id = id_list[gametextarray[index]];
        //var game_info = games_info[curr_id];

        var curr_text = gametextarray[index];
        var game_info = games_text_info[curr_text];
        //console.log("curr", curr_id, game_info);

        removeChildren(element);
        var ratingstr = '';
        ratingstr = ratingstr.concat('User: ');
        if (game_info.rating) {
            ratingstr = ratingstr.concat(Math.round(game_info.rating).toString());
            ratingstr = ratingstr.concat(' (' + game_info.rating_count.toString() + ')');
        } else {
            ratingstr = ratingstr.concat('/');
        }
        ratingstr = ratingstr.concat(', ');
        ratingstr = ratingstr.concat('Critics: ');
        if (game_info.aggregated_rating) {
            ratingstr = ratingstr.concat(Math.round(game_info.aggregated_rating).toString());
            ratingstr = ratingstr.concat(' (' + game_info.aggregated_rating_count.toString() + ')');
        } else {
            ratingstr = ratingstr.concat('/');
        }
        ratingstr = ratingstr.concat(', ');
        ratingstr = ratingstr.concat('Total: ');
        if (game_info.total_rating) {
            ratingstr = ratingstr.concat(Math.round(game_info.total_rating).toString());
            ratingstr = ratingstr.concat(' (' + game_info.total_rating_count.toString() + ')');
        } else {
            ratingstr = ratingstr.concat('/');
        }
        element.nodeValue = ratingstr;
    });
}

async function gather_genres() {
    var genresurl = corsproxy + apiurl + '/genres/' + Object.keys(genres_list).toString();
    //console.log("genres list", genres_list);
    console.log("genres url", genresurl);
    fetch(genresurl, {headers: myheaders})
        .then(res => res.json())
        .then(function (data) {
            //console.log("gg", genrenodesarray);
            console.log('genres', data);
            //console.log("games_info",games_info);
            //console.log("id_list",id_list);
            genresnodearray.forEach(function (element, index) {
                removeChildren(element);
                //console.log("index", index);
                //var curr_id = id_list[gametextarray[index]];
                var curr_text = gametextarray[index];
                //console.log("curr_id", curr_id);
                var game_info = games_text_info[curr_text];
                console.log("info",game_info);
                if(game_info.genres){
                  var curr_genre_ids = game_info.genres;
                  for (let genre_id of curr_genre_ids) {
                      //console.log("genre_id",genre_id);
                      var curr_genre = data.find(item => item.id == genre_id);
                      //console.log("curr_genre", curr_genre);
                      var newgenre = document.createElement('a');
                      newgenre.setAttribute("href", curr_genre.url);
                      newgenre.appendChild(document.createTextNode(curr_genre.name + ', '));
                      element.appendChild(newgenre);
                }
                }
                else {
                  element.appendChild(document.createTextNode("n/a"));
                }
                

            });
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

async function gather_kws() {
    var kwurl = corsproxy + apiurl + '/genres/' + Object.keys(genres_list).toString();
    //console.log("genres list", genres_list);
    console.log("kw", kwurl);
    fetch(kwurl, {headers: myheaders})
        .then(res => res.json())
        .then(function (data) {
            //console.log("gg", genrenodesarray);
            console.log('kws', data);
            //console.log("games_info",games_info);
            //console.log("id_list",id_list);
            keywordsnodearray.forEach(function (element, index) {
                removeChildren(element);
                //console.log("index", index);
                //var curr_id = id_list[gametextarray[index]];
                var curr_text = gametextarray[index];
                //console.log("curr_id", curr_id);
                var game_info = games_text_info[curr_text];
                if(game_info.keywords){
                  var curr_kw_ids = game_info.keywords;
                  for (let kw_id of curr_kw_ids) {
                    //console.log("genre_id",genre_id);
                    var curr_kw = data.find(item => item.id == kw_id);
                    //console.log("curr_genre", curr_genre);
                    var newkw = document.createElement('a');
                    newgenre.setAttribute("href", curr_kw.url);
                    newgenre.appendChild(document.createTextNode(curr_kw.name + ', '));
                    element.appendChild(newkw);
                  }
                }
                else {
                  element.appendChild(document.createTextNode("n/a"));
                }
                
            });
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

function gather_games_text_info(textarray) {
    var sliced = textarray;
    return Promise.all(sliced.map(text =>
        new Promise((resolve, reject) => {
            var info = load_info_by_text(text);
            info
                .then(data =>
                    new Promise((resolve2, reject2) => {

                        var curr_info = data[0];
                        //console.log("curr_info",curr_info);
                        games_text_info[text] = curr_info;
                        if (curr_info.genres) {
                            for (let genre of curr_info.genres) {
                                //console.log("genre_num",genre);
                                genres_list[genre] = genre;

                            }
                        }
                        if (curr_info.keywords) {
                            for (let kw of curr_info.keywords) {
                                keyword_list[kw] = kw;
                            }
                        }
                        resolve2("resolve2");
                    })
                        .catch(function (err) {
                            console.log(err.message);
                            console.log(err.stack);
                        })
                )
                .then(function () {
                    console.log("resolve", text)
                    resolve("resolve");
                })
                .catch(function (err) {
                    console.log(err.message);
                    console.log(err.stack);
                });
        })
    ))
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });


}


function gather_games_info(textarray) {


    //var sliced = textarray.slice(0,2);
    var sliced = textarray;
    console.log("Try loading for:", sliced);
    return Promise.all(sliced.map(text =>
        new Promise((resolve, reject) => {
            var curr_id = get_game_id_by_text(text);
            curr_id
                .then(id =>
                    new Promise((resolve2, reject2) => {
                        id_list[text] = id;
                        var info = load_info_by_id(id);
                        info.then(
                            function (result) {
                                return result;
                            }
                        )
                            .then(data =>
                                new Promise((resolve3, reject3) => {
                                    var curr_info = data[0];
                                    games_info[id] = curr_info;

                                    //console.log("curr_info",curr_info);
                                    if (curr_info.genres) {
                                        for (let genre of curr_info.genres) {
                                            //console.log("genre_num",genre);
                                            genres_list[genre] = genre;

                                        }
                                        //console.log("genres",curr_info.genres);
                                    }
                                    if (curr_info.keywords) {
                                        for (let kw of curr_info.keywords) {
                                            keyword_list[kw] = kw;
                                        }
                                    }
                                    //console.log("resolve3");
                                    resolve3("resolve3");
                                })
                            )
                            .then(function () {
                                //console.log("resolve2");
                                resolve2("resolve2");
                            })
                            .catch(function (err) {
                                console.log(err.message);
                                console.log(err.stack);
                            });

                    })
                )
                .then(function () {
                    //console.log("info", games_info);
                    console.log("resolve", text);

                    resolve("resolve");
                    //return true;
                })
                .catch(function (err) {
                    console.log(err.message);
                    console.log(err.stack);
                });
        })
    ))
        .then(function (data2) {
            console.log("glist", genres_list);
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

async function load_info_by_text(text) {
    var text_url = (corsproxy + apiurl + req + text + "&" + fieldsall);
    return fetch(text_url,
        {
            headers: myheaders
        }
    )
        .then(res => res.json())
        .then(function (data) {
            //console.log("data",data);
            return data;
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

async function load_info_by_id(id) {
    var id_url = (corsproxy + apiurl + '/games/' + id + fields);
    return fetch(id_url, {headers: myheaders})
        .then(res => res.json())
        .then(function (data) {
            return data;
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

function get_game_id_by_text(text) {
    return fetch(corsproxy + apiurl + req + text, {headers: myheaders})
        .then(res => res.json())
        .then(function (data) {
            var game_id_num = data[0].id;
            var game_id = game_id_num.toString();
            return game_id;
        })
        .catch(function (err) {
            console.log(err.message);
            console.log(err.stack);
        });
}

function load_single_by_text(text, index) {
    var result = fetch(corsproxy + apiurl + req + text, {headers: myheaders})
        .then(res => res.json())
        .then(function (data) {
            var game_id_num = data[0].id;
            id_list.push(game_id_num);
            console.log("pushed", game_id_num);
            var game_id = game_id_num.toString();
            load_single_by_id(game_id, index, 1, 0, 0);
            return data;
        });
}

/*--- waitForKeyElements():  A utility function, for Greasemonkey scripts,
    that detects and handles AJAXed content.

    Usage example:

        waitForKeyElements (
            "div.comments"
            , commentCallbackFunction
        );

        //--- Page-specific function to do what we want when the node is found.
        function commentCallbackFunction (jNode) {
            jNode.text ("This comment changed by waitForKeyElements().");
        }

    IMPORTANT: This function requires your script to have loaded jQuery.
*/
function waitForKeyElements(
    selectorTxt,
    /* Required: The jQuery selector string that
                                specifies the desired element(s).
               */
    actionFunction,
    /* Required: The code to run when elements are
                                found. It is passed a jNode to the matched
                                element.
               */
    bWaitOnce,
    /* Optional: If false, will continue to scan for
                                new elements even after the first match is
                                found.
               */
    iframeSelector
    /* Optional: If set, identifies the iframe to
                                search.
               */
) {
    var targetNodes, btargetsFound;

    if (typeof iframeSelector == "undefined")
        targetNodes = $(selectorTxt);
    else
        targetNodes = $(iframeSelector).contents()
            .find(selectorTxt);

    if (targetNodes && targetNodes.length > 0) {
        btargetsFound = true;
        /*--- Found target node(s).  Go through each and act if they
            are new.
   */
        targetNodes.each(function () {
            var jThis = $(this);
            var alreadyFound = jThis.data('alreadyFound') || false;

            if (!alreadyFound) {
                //--- Call the payload function.
                var cancelFound = actionFunction(jThis);
                if (cancelFound)
                    btargetsFound = false;
                else
                    jThis.data('alreadyFound', true);
            }
        });
    } else {
        btargetsFound = false;
    }

    //--- Get the timer-control variable for this selector.
    var controlObj = waitForKeyElements.controlObj || {};
    var controlKey = selectorTxt.replace(/[^\w]/g, "_");
    var timeControl = controlObj[controlKey];

    //--- Now set or clear the timer as appropriate.
    if (btargetsFound && bWaitOnce && timeControl) {
        //--- The only condition where we need to clear the timer.
        clearInterval(timeControl);
        delete controlObj[controlKey];
    } else {
        //--- Set a timer, if needed.
        if (!timeControl) {
            timeControl = setInterval(function () {
                    waitForKeyElements(selectorTxt,
                        actionFunction,
                        bWaitOnce,
                        iframeSelector
                    );
                },
                300
            );
            controlObj[controlKey] = timeControl;
        }
    }
    waitForKeyElements.controlObj = controlObj;
}