/*
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 += `- ${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();
});
}