Gates of Survival - Active Players scraper

Shows active player data in table format. Based on Opal's Action Scraper: https://greasyfork.org/en/scripts/31091-action-scraper

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Gates of Survival - Active Players scraper
// @namespace   https://www.gatesofsurvival.com
// @version     0.11
// @author      dang
// @homepage    https://github.com/dang-nabbit/gos-active-players-scraper
// @description Shows active player data in table format. Based on Opal's Action Scraper: https://greasyfork.org/en/scripts/31091-action-scraper
// @match       https://www.gatesofsurvival.com/game/online.php
// @icon        https://www.google.com/s2/favicons?domain=https://www.gatesofsurvival.com/
// @grant       none
// ==/UserScript==

// Settings
var summaryShortSkillNames = true; // Turn off if you want full skill names on summary header
var ldLNOnTop = true; // Turn off if you don't want LD/LN to be first clans listed
var italicSkills = ['Agility']; // Make listed skills italic in player list
var boldSkills = ['Not skilling']; // Make listed skills bold in player list
var underlineSkills = ['Fishing']; // Make listed skills underlined in player list
// Settings end

var profileURL = 'https://www.gatesofsurvival.com/game/user2.php?user=';

var errors = [];
var clans = [];
var noClan = {
    initials: 'None',
    players: [],
    skills: []
};
var hardcore = {
    initials: 'HC',
    players: [],
    skills: []
};
var ironman = {
    initials: 'IM',
    players: [],
    skills: []
};
var totals = {
    initials: 'Total',
    players: [],
    skills: []
};
var ld;
var ln;

var playerTypes = [
    'Hardcore Ironman',
    'Ironman'
];
var numPlayerTypes = playerTypes.length;

var skills = [
    {
        name: 'Agility',
        short: 'Agil'
    }, {
        name: 'Arcane',
        short: 'Arcn'
    }, {
        name: 'Archery',
        short: 'Arch'
    }, {
        name: 'Baking',
        short: 'Bakn'
    }, {
        name: 'Botany',
        short: 'Bota'
    }, {
        name: 'Cooking',
        short: 'Cook'
    }, {
        name: 'Crafting',
        short: 'Crft'
    }, {
        name: 'Divination',
        short: 'Divn'
    }, {
        name: 'Exploration',
        short: 'Expl'
    }, {
        name: 'Fighting',
        short: 'Fght'
    }, {
        name: 'Firemaking',
        short: 'Fire'
    }, {
        name: 'Fishing',
        short: 'Fish'
    }, {
        name: 'Fletching',
        short: 'Flet'
    }, {
        name: 'Forestry',
        short: 'Frst'
    }, {
        name: 'Forging',
        short: 'Forg'
    }, {
        name: 'Gathering',
        short: 'Gthr'
    }, {
        name: 'Hunting',
        short: 'Hunt'
    }, {
        name: 'Jewelcrafting',
        short: 'Jwel'
    }, {
        name: 'Looting',
        short: 'Loot'
    }, {
        name: 'Mining',
        short: 'Mini'
    }, {
        name: 'Prayer',
        short: 'Pray'
    }, {
        name: 'Runebinding',
        short: 'Rnbd'
    }, {
        name: 'Skinning',
        short: 'Skin'
    }, {
        name: 'Slaying',
        short: 'Slay'
    }, {
        name: 'Smelting',
        short: 'Smlt'
    }, {
        name: 'Spellcraft',
        short: 'Spll'
    }, {
        name: 'Summoning',
        short: 'Smmn'
    }, {
        name: 'Thieving',
        short: 'Thvn'
    }, {
        name: 'Transmutation',
        short: 'Tran'
    }, {
        name: 'Woodworking',
        short: 'Wood'
    }, {
        name: 'Not skilling',
        short: 'None'
    }
];
var numSkills = skills.length;

function addGlobalStyle(css, head) {
    var style;
    head = head || document.getElementsByTagName('head')[0];
    style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = css;
    head.appendChild(style);
}

function formatPercentage(number) {
    return (number * 100).toFixed(1) + '%';
}

function addClanSkillCount(clan) {
    var skill;

    for (var i = 0; i < numSkills; i++) {
        skill = skills[i];

        clan.skills.push({
            name: skill.name,
            count: 0
        });
    }
}

function scrapePlayer(tdInnerHTML) {
    var mainRegEx = /<img src="images\/crowns\/(.+?)\.png".*?>.*?<input value="(\d+)".*?><input.*?>(.+?)<\/.*?<\/form>.*?\(Last Active: (.+?)\)/;
    var activityRegEx = /<b>Currently<\/b>: (.+?)<br>/;
    var clanRegex = /<b>Clan<\/b>: \[(.+?)\]/;

    var result = mainRegEx.exec(tdInnerHTML);

    var player = {};
    var crown;
    var activityResult;
    var activity;
    var skill;
    var type;
    var clanResult;
    var i;

    if (result === null) {
        return {
            error: 'Player data not recognized',
            content: tdInnerHTML
        };
    } else {
        player = {
            id: result[2],
            name: result[3],
            lastActive: result[4]
        };

        crown = result[1];
        if (crown.indexOf('crown_') > -1) {
            player.rank =  crown.replace('crown_', '');
        } else if (crown === 'sponsor') {
            player.rank = 'Sponsor';
        } else {
            player.rank = 'Unidentified';
        }

        activityResult = activityRegEx.exec(tdInnerHTML);

        if (activityResult !== null) {
            activity = activityResult[1];

            for (i = 0; i < numSkills; i++) {
                skillName = skills[i].name;
                if (activity.indexOf(skillName) > -1) {
                    player.skill = skillName;

                    if (skillName === 'Fighting') {
                        player.mob = activity.replace('Fighting a ', '');
                    }

                    break;
                }
            }
        }
        if (!player.skill) {
            player.skill = 'Not skilling';
            player.activity = activity || 'None';
        }


        for (i = 0; i < numPlayerTypes; i++) {
            type = playerTypes[i];
            if (tdInnerHTML.indexOf(type) > -1) {
                player.type = type;
                break;
            }
        }

        clanResult = clanRegex.exec(tdInnerHTML);
        if (clanResult !== null) {
            player.clan = clanResult[1];
        }
    }

    return player;
}

function addPlayerToList(td) {
    var player = scrapePlayer(td.innerHTML);
    var playerClan = player.clan;
    var playerType = player.type;
    var clan = {};
    var skill;
    var skillObj;

    if (player.error) {
        errors.push(player);
    } else if (playerClan) {
        clan = clans.find(function(clan) {return clan.initials === playerClan;});
        if (!clan) {
            clan = {
                initials: playerClan,
                players: [],
                skills: []
            };

            addClanSkillCount(clan);

            if (['LD', 'LN'].indexOf(playerClan) > -1) {
                if (playerClan === 'LD') {
                    ld = clan;
                } else if (playerClan === 'LN') {
                    ln = clan;
                }

                if (ldLNOnTop) {
                    clans.splice(0, 0, clan);
                }
            } else {
                clans.push(clan);
            }
        }
    } else if (playerType === 'Hardcore Ironman') {
        clan = hardcore;
    } else if (playerType === 'Ironman') {
        clan = ironman;
    } else {
        clan = noClan;
    }

    skillObj = clan.skills.find(function(skill) {return skill.name === player.skill;});
    skillObj.count++;
    skillObj = totals.skills.find(function(skill) {return skill.name === player.skill;});
    skillObj.count++;

    clan.players.push(player);
    totals.players.push(player);
}

function scrapeAll() {
    document.querySelectorAll('#third-container5 td').forEach(addPlayerToList);
}

function getErrorsTable() {
    var numErrors = errors.length;
    var div = document.createElement('div');

    if (numErrors > 0) {
        var title = document.createElement('b');
        title.appendChild(document.createTextNode('Errors'));
        div.appendChild(title);

        var table = document.createElement('table');
        div.appendChild(table);

        div.appendChild(document.createElement('hr'));

        var row = table.insertRow();
        var errorCell = row.insertCell();
        errorCell.outerHTML = '<th>Error</th>';
        var errorContentCell = row.insertCell();
        errorContentCell.outerHTML = '<th>Content</th>';

        var error;
        for (var i = 0; i < numErrors; i++) {
            error = errors[i];

            row = table.insertRow();

            errorCell = row.insertCell();
            errorCell.appendChild(document.createTextNode(error.error || ''));

            errorContentCell = row.insertCell();
            errorContentCell.appendChild(document.createTextNode(error.content || ''));
        }
    }

    return div;
}

function getPlayerTable(clan) {
    var players = clan.players;
    var numPlayers = players.length;
    var div = document.createElement('div');

    if (numPlayers > 0) {
        var title = document.createElement('b');
        title.appendChild(document.createTextNode(clan.initials));
        div.appendChild(title);

        var table = document.createElement('table');
        div.appendChild(table);

        div.appendChild(document.createElement('hr'));

        var row = table.insertRow();
        var nameCell = row.insertCell();
        nameCell.outerHTML = '<th>Name</th>';
        var idCell = row.insertCell();
        idCell.outerHTML = '<th>ID</th>';

        var lastActiveCell = row.insertCell();
        lastActiveCell.outerHTML = '<th>Last active</th>';
        var rankCell = row.insertCell();
        rankCell.outerHTML = '<th>Rank</th>';
        var skillCell = row.insertCell();
        skillCell.outerHTML = '<th>Skill</th>';
        var mobCell = row.insertCell();
        mobCell.outerHTML = '<th>Enemy</th>';
        var activityCell = row.insertCell();
        activityCell.outerHTML = '<th>Activity</th>';

        var player;
        var playerAnchor;
        var playerSkill;
        for (var i = 0; i < numPlayers; i++) {
            player = players[i];

            row = table.insertRow();

            nameCell = row.insertCell();
            playerAnchor = document.createElement('a');
            playerAnchor.href = profileURL + (player.name || '');
            playerAnchor.target = '_blank';
            playerAnchor.appendChild(document.createTextNode(player.name || ''));
            nameCell.appendChild(playerAnchor);

            idCell = row.insertCell();
            idCell.classList.add('number-cell');
            idCell.appendChild(document.createTextNode(player.id || ''));

            lastActiveCell = row.insertCell();
            lastActiveCell.appendChild(document.createTextNode(player.lastActive || ''));

            rankCell = row.insertCell();
            rankCell.classList.add('number-cell');
            rankCell.appendChild(document.createTextNode(player.rank || ''));

            playerSkill = player.skill;
            skillCell = row.insertCell();
            skillCell.appendChild(document.createTextNode(playerSkill || ''));
            if (italicSkills.indexOf(playerSkill) > -1) {
                skillCell.classList.add('italic');
            }
            if (boldSkills.indexOf(playerSkill) > -1) {
                skillCell.classList.add('bold');
            }
            if (underlineSkills.indexOf(playerSkill) > -1) {
                skillCell.classList.add('underline');
            }

            mobCell = row.insertCell();
            mobCell.appendChild(document.createTextNode(player.mob || ''));

            activityCell = row.insertCell();
            activityCell.appendChild(document.createTextNode(player.activity || ''));
        }
    }

    return div;
}

function getSummary() {
    // In summary, show clans and add other categories at end
    var summaryClans = clans.concat([noClan, ironman, hardcore, totals]);
    var numSummaryClans = summaryClans.length;
    var i;
    var j;

    var div = document.createElement('div');

    // Title
    var title = document.createElement('b');
    title.appendChild(document.createTextNode('Summary'));
    div.appendChild(title);

    var table = document.createElement('table');
    div.appendChild(table);

    // Header row
    var row = table.insertRow();

    // Clan name header
    var clanCell = row.insertCell();
    clanCell.outerHTML = '<th>Clan</th>';

    // Skill headers
    var skillCell;
    var skillHeader = (summaryShortSkillNames) ? 'short' : 'name'
    for (i = 0; i < numSkills; i++) {
        skillCell = row.insertCell();
        skillCell.outerHTML = '<th>' + skills[i][skillHeader] + '</th>';
    }

    // Total column header
    var clanTotalCell = row.insertCell();
    clanTotalCell.outerHTML = '<th>Total</th>';

    // Total % column header
    var clanTotalPercCell = row.insertCell();
    clanTotalPercCell.outerHTML = '<th>%</th>';

    // Lucky % row
    row = table.insertRow();

    // Lucky % "clan name"
    clanCell = row.insertCell();
    clanCell.appendChild(document.createTextNode('L%'));

    // Lucky % skill numbers
    var totalPlayers = ld.players.length + ln.players.length;
    for (i = 0; i < numSkills; i++) {
        skillCell = row.insertCell();
        skillCell.classList.add('number-cell');
        skillCell.appendChild(document.createTextNode(formatPercentage((ld.skills[i].count + ln.skills[i].count)/totalPlayers)));
    }

    // Empty total and total % cells for Lucky %
    clanTotalCell = row.insertCell();
    clanTotalCell.classList.add('number-cell');

    clanTotalPercCell = row.insertCell();
    clanTotalPercCell.classList.add('number-cell');

    var clan;
    totalPlayers = totals.players.length;
    for (i = 0; i < numSummaryClans; i++) {
        clan = summaryClans[i];

        // Clan row
        row = table.insertRow();

        // Clan name cell
        clanCell = row.insertCell();
        clanCell.appendChild(document.createTextNode(clan.initials));

        // Clan skill numbers
        for (j = 0; j < numSkills; j++) {
            skillCell = row.insertCell();
            skillCell.classList.add('number-cell');
            skillCell.appendChild(document.createTextNode(clan.skills[j].count));
        }

        // Clan total count
        clanTotalCell = row.insertCell();
        clanTotalCell.classList.add('number-cell');
        clanTotalCell.appendChild(document.createTextNode(clan.players.length));

        // Clan total %
        clanTotalPercCell = row.insertCell();
        clanTotalPercCell.classList.add('number-cell');
        clanTotalPercCell.appendChild(document.createTextNode(formatPercentage(clan.players.length/totalPlayers)));
    }

    // % row
    row = table.insertRow();

    // % name cell
    clanCell = row.insertCell();
    clanCell.appendChild(document.createTextNode('%'));

    // % skill numbers
    for (j = 0; j < numSkills; j++) {
        skillCell = row.insertCell();
        skillCell.classList.add('number-cell');
        skillCell.appendChild(document.createTextNode(formatPercentage(totals.skills[j].count/totalPlayers)));
    }

    // Empty total and total % cells for Lucky %
    clanTotalCell = row.insertCell();
    clanTotalCell.classList.add('number-cell');

    clanTotalPercCell = row.insertCell();
    clanTotalPercCell.classList.add('number-cell');

    return div;
}

function addReportStyles(doc) {
    var css = '.italic {\n' +
        '    font-style: italic;\n' +
        '}\n\n' +
        '.bold {\n' +
        '    font-weight: bold;\n' +
        '}\n\n' +
        '.underline {\n' +
        '    text-decoration: underline;\n' +
        '}\n\n' +
        '.number-cell {\n' +
        '    text-align: right;\n' +
        '    padding-right: 3px;\n' +
        '}';
    addGlobalStyle(css, doc.head);
}

function printDataTables() {
    addClanSkillCount(noClan);
    addClanSkillCount(ironman);
    addClanSkillCount(hardcore);
    addClanSkillCount(totals);
    scrapeAll();

    var reportDoc = window.open().document;
    addReportStyles(reportDoc);

    var reportBody = reportDoc.body;
    reportBody.appendChild(getErrorsTable());

    var numClans = clans.length;
    for (var i = 0; i < numClans; i++) {
        reportBody.appendChild(getPlayerTable(clans[i]));
    }

    reportBody.appendChild(getPlayerTable(noClan));
    reportBody.appendChild(getPlayerTable(ironman));
    reportBody.appendChild(getPlayerTable(hardcore));

    reportBody.appendChild(getSummary());
}

printDataTables();