/* Pouët Top List Generator V2 1 - Log in to http://www.pouet.net 2 - Goto topic - http://www.pouet.net/topic.php?which=10190 3 - Enter javascript console mode 4 - paste script. 5 - Enjoy https://luis.net/personal/pouet/toplist 2020 - https://www.pouet.net/topic.php?which=12045 2019 - https://www.pouet.net/topic.php?which=11825 2018 - https://www.pouet.net/topic.php?which=11610 2017 - https://www.pouet.net/topic.php?which=11288 2016 - ? 2015 - https://www.pouet.net/topic.php?which=10592 2014 - https://www.pouet.net/topic.php?which=10190 2013 - https://www.pouet.net/topic.php?which=9734 2012 - ? 2011 - https://www.pouet.net/topic.php?which=8536 2010 - https://www.pouet.net/topic.php?which=7852 2009 - https://www.pouet.net/topic.php?which=7061 */ var topListObject = {}; var platforms = []; var promiseArray = []; var year = 2020; var addProdByCategory = function(categoryName, prodID, voteup) { topListObject[categoryName] = topListObject[categoryName] || []; topListObject[categoryName].push({ id: prodID, voteup: voteup }); }; new Ajax.JSONRequest(`https://api.pouet.net/adhoc/prods-from-year?year=${year}`, { onSuccess: function(transport) { var obj = transport.responseJSON; console.info(`${obj.prods.length + 1} prods in ${year}`); console.info(`please wait until you see DONE...`); let prodArray = []; for (i = 0; i < obj.prods.length; i++) { // for (i = 0; i < 25; i++) { // for testing prodArray.push(obj.prods[i].id) } rateLimitMap(prodArray, 5, 10, getProdInfo).then(function(results) { // process array of results here console.info('DONE'); console.info("platforms", platforms); console.log('topListObject', topListObject); build(); }, function(err) { console.warn('something went wrong'); }); } }); function build(obj) { var prodLinks = ''; for (const property in topListObject) { if (topListObject.hasOwnProperty(property)) { prodLinks += `[list=1][b]Top ${topListObject[property].length > 25 ? 25 : topListObject[property].length} ${property}[/b]\n\n`; // prodLinks += `
    Top ${topListObject[property].length > 25 ? 25 : topListObject[property].length} ${property}

    `; // sort by number of votes let sorted = topListObject[property].sort((a, b) => { return parseInt(b.voteup) - parseInt(a.voteup); }); // limit to 25 otherwise we'll have top 168 C64 prods for (var i = 0; i < sorted.length; i++) { if (i < 25) { prodLinks += platforms[sorted[i].id].bbCode; prodLinks += "\n"; } } prodLinks += `[/list]\n`; // prodLinks += `
\n`; } } // generate top 25 prods accross everything var topLinks = ''; var sortedProds = platforms.sort((a, b) => { return parseInt(b.voteup) - parseInt(a.voteup); }); topLinks += `[list=1][b]Top ${sortedProds.length > 25 ? 25 : sortedProds.length} Productions[/b]\n\n`; //topLinks += `
    Top ${sortedProds.length > 25 ? 25 : sortedProds.length} Productions

    `; //topLinks += `
      \n`; prodLinks += `[list]\n`; // limit to 25 otherwise we'll have top 168 C64 prods for (var i = 0; i < sortedProds.length; i++) { if (i < 25) { topLinks += sortedProds[i].bbCode; topLinks += "\n"; } } // topLinks += `
    \n`; prodLinks += `[/list]\n`; // write results to info box document.getElementById("message").value = topLinks + prodLinks; } async function getProdInfo(prodID) { return new Promise(resolve => { new Ajax.JSONRequest("https://api.pouet.net/v1/prod/?id=" + prodID, { onSuccess: function(transport) { var obj = transport.responseJSON.prod; var prodLinks = ''; prodLinks += `[*][url=https://www.pouet.net/prod.php?which=${prodID}]${obj.name}[/url]`; // prodLinks += `
  1. ${obj.name}`; if (obj.groups.length > 0) { prodLinks += " by "; obj.groups.each(function(groupObj, j) { if (j > 0) prodLinks += " & "; prodLinks += `[url=https://www.pouet.net/groups.php?which=${groupObj.id}]${groupObj.name}[/url]`; // prodLinks += `${groupObj.name}`; }); } // add to prodid links platforms[prodID] = { bbCode: prodLinks, voteup: obj.voteup // to count all time top }; // add by platform for (const property in obj.platforms) { addProdByCategory(obj.platforms[property].name, prodID, obj.voteup); } // add by type for (const property in obj.types) { if (obj.types.hasOwnProperty(property)) { addProdByCategory(obj.types[property], prodID, obj.voteup); } } resolve(); } }); }); } // pass the following arguments: // array - array of values to iterate // requestsPerSec - max requests per second to send (integer) // maxInFlight - max number of requests in process at a time // fn - function to process an array value // function is passed array element as first argument // function returns a promise that is resolved/rejected when async operation is done // Returns: promise that is resolved with an array of resolves values // or rejected with first error that occurs function rateLimitMap(array, requestsPerSec, maxInFlight, fn) { return new Promise(function(resolve, reject) { var index = 0; var inFlightCntr = 0; var doneCntr = 0; var launchTimes = []; var results = new Array(array.length); // calculate num requests in last second function calcRequestsInLastSecond() { var now = Date.now(); // look backwards in launchTimes to see how many were launched within the last second var cnt = 0; for (var i = launchTimes.length - 1; i >= 0; i--) { if (now - launchTimes[i] < 1000) { ++cnt; } else { break; } } return cnt; } function runMore() { while (index < array.length && inFlightCntr < maxInFlight && calcRequestsInLastSecond() < requestsPerSec) { (function(i) { ++inFlightCntr; launchTimes.push(Date.now()); fn(array[i]).then(function(val) { results[i] = val; --inFlightCntr; ++doneCntr; runMore(); }, reject); })(index); ++index; } // see if we're done if (doneCntr === array.length) { resolve(results); } else if (launchTimes.length >= requestsPerSec) { // calc how long we have to wait before sending more var delta = 1000 - (Date.now() - launchTimes[launchTimes.length - requestsPerSec]); if (delta >= 0) { setTimeout(runMore, ++delta); } } } runMore(); }); }