Skip to content

Instantly share code, notes, and snippets.

@McMaNGOS
Last active April 22, 2018 04:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save McMaNGOS/88f8e90389431d04aaee0be24764b68f to your computer and use it in GitHub Desktop.
Save McMaNGOS/88f8e90389431d04aaee0be24764b68f to your computer and use it in GitHub Desktop.
eAmusement beatmania IIDX DJ DATA scores -> JSON
/* Cheerio-powered parser for the DJ DATA score page on the beatmania IIDX website.
Requires 'cheerio', 'request', and 'iconv' packages.
Needs 'Cookie' header from manual login for authentication.
Results in an array of JSON-formatted scores, which looks like this:
{
"songs": [{
"song": {
"name": "SONG NAME",
"normal": {
"lamp": "NO PLAY/CLEAR/HARD CLEAR/etc",
"grade": "C/B/A/etc",
"score": "0(0/0)"
},
"hyper": {
"lamp": "NO PLAY/CLEAR/HARD CLEAR/etc",
"grade": "C/B/A/etc",
"score": "0(0/0)"
},
"another": {
"lamp": "NO PLAY/CLEAR/HARD CLEAR/etc",
"grade": "C/B/A/etc",
"score": "0(0/0)"
}
}
}]
}
*/
var cheerio = require('cheerio');
var req = require('request');
var Iconv = require('iconv').Iconv;
var $;
/* Makes a POST request to get the scores page we want, then executes parseTable with the response.
Log in to your account and replace 'YOUR_COOKIE_HERE' with the 'Cookie' header from your browser.
This allows for authentication without username/password/captcha. */
req.post({
url: 'https://p.eagate.573.jp/game/2dx/24/p/djdata/music/series.html',
// "list": IIDX version (counting from zero, so SINOBUZ is 23).
// "play_style": 0 for SP, 1 for DP.
// "rival": For checking rival scores, I guess? No idea.
// "s": Again, not sure...
// "page": For pagination, counting from 1.
form: { list: 23, play_style: 0, rival: '', s: 1, page: 1 },
encoding: null,
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36',
'Content-Type' : 'application/x-www-form-urlencoded',
'Cookie' : 'YOUR_COOKIE_HERE'
},
method: 'POST'
},
// This executes when the response has been received.
function (e, r, body) {
// gotta re-encode response the page ourselves (shoutout to all the mojibake)
body = new Iconv('shift_jis', 'utf-8').convert(body).toString();
// load the response with cheerio, then parse
$ = cheerio.load(body);
parseTable($);
});
/* Takes clear lamp image src, grade image src, and score as input.
Processes the image src's to get clear lamp and grade, then returns a score object. */
function createScoreEntry(inClear, inGrade, inScore) {
var clearMap = {
"0": "NO PLAY",
"1": "FAILED",
"2": "ASSIST CLEAR",
"3": "EASY CLEAR",
"4": "CLEAR",
"5": "HARD CLEAR",
"6": "EX HARD CLEAR",
"7": "FULL COMBO"
}
if (inClear === undefined) {
inClear = "error in clear";
} else {
inClear = inClear.match(/(\d)\./g)[0].slice(0, -1); // get number from img src
inClear = clearMap[inClear]; // get clear type from map
}
if (inGrade === undefined) {
inGrade = "error in grade";
} else if (inGrade.indexOf("---.gif") >= 0) {
inGrade = "NO PLAY";
} else {
// set grade based on image filename (e.g. "A.gif" => "A")
inGrade = inGrade.match(/(\w+)\./g)[0].slice(0, -1);
}
return {
"lamp": inClear,
"grade": inGrade,
"score": inScore
}
}
/* Takes song name and three score objects (one for each difficulty) as input.
Returns a song object, which is basically just an outer wrapper for the input. */
function createSongEntry(name, normal, hyper, another) {
var song = {
"name": name,
"normal": normal,
"hyper": hyper,
"another": another
}
return { "song": song };
}
var songs = [];
/* Takes HTML page as input, and gets all the scores from the table element.
For each entry in the table, it extracts & processes the song name, lamp, grade, and score.
It then creates a song object out of these, then pushes that object to the "songs" array.
The output array is then turned into valid JSON, wrapped in an outer "songs" object, and printed. */
function parseTable($) {
$('table.table_type_list td').each(function(i, el) {
var songName = $('a', this).text();
var normalLamp = $('div.clear_info div.clear_cel:nth-child(1) img', this).attr('src');
var normalGrade = $('div.clear_info div.clear_cel:nth-child(1) img[alt="DJLEVEL画像"]', this).attr('src');
var normalScore = $('div.clear_info div.clear_cel:nth-child(1)', this).text()
.replace(/\r?\n|\r/g, '')
.replace("NORMAL", "")
.replace(/^\s+|\s+$|\s+(?=\s)/g, "");
var normal = createScoreEntry(normalLamp, normalGrade, normalScore);
var hyperLamp = $('div.clear_info div.clear_cel:nth-child(2) img', this).attr('src');
var hyperGrade = $('div.clear_info div.clear_cel:nth-child(2) img[alt="DJLEVEL画像"]', this).attr('src');
var hyperScore = $('div.clear_info div.clear_cel:nth-child(2)', this).text()
.replace(/\r?\n|\r/g, '')
.replace("HYPER", "")
.replace(/^\s+|\s+$|\s+(?=\s)/g, "");
var hyper = createScoreEntry(hyperLamp, hyperGrade, hyperScore);
var anotherLamp = $('div.clear_info div.clear_cel:nth-child(3) img', this).attr('src');
var anotherGrade = $('div.clear_info div.clear_cel:nth-child(3) img[alt="DJLEVEL画像"]', this).attr('src');
var anotherScore = $('div.clear_info div.clear_cel:nth-child(3)', this).text()
.replace(/\r?\n|\r/g, '')
.replace("ANOTHER", "")
.replace(/^\s+|\s+$|\s+(?=\s)/g, "");
var another = createScoreEntry(anotherLamp, anotherGrade, anotherScore);
var song = createSongEntry(songName, normal, hyper, another);
songs.push(song);
});
songs = songs.map(function(e) {
return JSON.stringify(e);
});
console.log('{ "songs" : [' + songs.join(",") + '] }');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment