TagPro Groups on Homepage

Show available groups *of all servers* on the homepage, joiner page and inside a group

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         TagPro Groups on Homepage
// @version      2.4
// @description  Show available groups *of all servers* on the homepage, joiner page and inside a group
// @author       Ko
// @supportURL   https://www.reddit.com/message/compose/?to=Wilcooo
// @website      https://redd.it/no-post-yet
// @download     https://raw.githubusercontent.com/wilcooo/TagPro-GroupsOnHomepage/master/tpgoh.user.js
// @match        http://*.koalabeast.com*
// @match        http://tagpro.gg/
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @license      MIT
// @icon         https://raw.githubusercontent.com/wilcooo/TagPro-GroupsOnHomepage/master/icon.png
// @require      https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.0/socket.io.slim.js
// @require      https://greasyfork.org/scripts/371240/code/TagPro%20Userscript%20Library.js
// @connect      koalabeast.com
// @namespace https://greasyfork.org/users/152992
// ==/UserScript==



/* global tagpro, io, tpul */



var short_name = 'groups_on_homepage'; // An alphabetic (no spaces/numbers, preferably lowercase) distinctive name for the script.
var version = GM_info.script.version; // The version number is automatically fetched from the metadata.
tagpro.ready(function(){ tagpro.scripts = Object.assign( tagpro.scripts || {}, {short_name:{version:version}} ); });
console.log('START: ' + GM_info.script.name + ' (v' + version + ' by ' + GM_info.script.author + ')');


// Userscripts load in the order that they appear in Tamermonkey.
// Set this option to true if you want this script to be inserted to
// the page above than previously load scripts, instead of below.
const insertBefore = false;


var settings = tpul.settings.addSettings({
    id: short_name,
    title: "Configure Groups on Homepage",
    tooltipText: "Groups on Homepage",
    icon: "https://raw.githubusercontent.com/wilcooo/TagPro-GroupsOnHomepage/master/icon.png",

    fields: {
        groups_on_home: {
            label: 'Show all public groups (worldwide) on the homepage',
            type: 'checkbox',
            default: true,
        },
        groups_on_find: {
            label: 'Show all public groups (worldwide) while finding a game',
            type: 'checkbox',
            default: true,
        },
        groups_on_groups: {
            label: 'Show all public groups (worldwide) on the /groups page, instead of just the current server\'s groups',
            type: 'checkbox',
            default: true,
        },
        groups_in_group: {
            label: 'Show all public groups (worldwide) while in a group',
            type: 'checkbox',
            default: true,
        },
        position: {
            label: 'Position of the groups on the homepage',
            type: 'select',
            options: ['top','bottom'],
            default: 'top',
        },
        interval: {
            label: 'How often should this script update the groups, so you don\'t have to F5 all the time? Choose an amount of seconds, or set to 0 to never update',
            type: 'int',
            min: 0,
            max: 600,
            default: 60
        },
    },

    events: {
        open: function () {

            // Changing the layout a bit after the config panel is opened...

            [...this.frame.getElementsByClassName('field_label')].forEach( function(el) {
                el.classList.remove('col-xs-4');
                el.classList.add('col-xs-8');
                el.nextElementSibling.classList.remove('col-xs-8');
                el.nextElementSibling.classList.add('col-xs-4');
            } );
        },
        save: function() {

            // Making sure (most) options take effect immediately after a save...

            position = settings.get("position");
            groups_on_home = settings.get("groups_on_home");
            groups_on_find = settings.get("groups_on_find");
            groups_on_groups = settings.get("groups_on_groups");
            groups_in_group = settings.get("groups_in_group");
            interval = settings.get("interval");


            // Update the position of the groups if necessary:

            var groups_div = document.getElementById('GroPro-groups');

            update_groups();

            groups_div.classList.remove('hidden');

            if (window.location.pathname === '/' && !groups_on_home ||
                window.location.pathname.match(/^\/groups\/[a-z]{8}$/) && !groups_in_group ||
                window.location.pathname === '/groups' && !groups_on_groups ||
                window.location.pathname === '/games/find' && !groups_on_find ) {

                groups_div.classList.add('hidden');
            }

        }
    }
});


var position = settings.get("position"),
    groups_on_home = settings.get("groups_on_home"),
    groups_on_find = settings.get("groups_on_find"),
    groups_on_groups = settings.get("groups_on_groups"),
    groups_in_group = settings.get("groups_in_group"),
    interval = settings.get("interval");






const servers = ['centra','pi','chord','diameter','origin','sphere','radius','orbit'];

// We don't use this api anymore, since anonymous xmlhttpRequests are now possible.
//const groups_api = 'https://script.google.com/macros/s/AKfycbxF5kcVoFbqmLlbHB2_nJ_dCRoh2iOXDpFyzAq0Kw2UDjM7qEHf/exec';


var warned = false;

function get_groups() {return new Promise(function(resolve,reject) {

    var parser = new DOMParser(),
        groups = [],
        pending = 0;

    servers.forEach(function(server) {

        pending ++;

        GM_xmlhttpRequest({
            url: 'http://tagpro-'+server+'.koalabeast.com/groups/',
            anonymous: true,
            onload: done,
            onerror: done,
            timeout: 5000,
            context: server,
        });
    });

    function done(response){

        pending --;

        if (response.finalUrl.includes('groupAuth')) {
            //if (!warned) warned = tagpro.helpers.displayError("Sorry, your IP address has been flagged - so the GroupsOnHome script can't yet show you the groups. No worries though, I'm working on a fix for this.");
            console.error("Sorry, your IP address has been flagged - so the GroupsOnHome script can't yet show you the groups. No worries though, I'm working on a fix for this.");
            groups.flagged = true;
        }

        if (response.response) {

            var groups_doc = parser.parseFromString(response.response, "text/html");
            for (var group_item of groups_doc.getElementsByClassName('group-item')) {

                var group = { server: response.context };
                groups.push(group);

                for (var el of group_item.querySelectorAll("*") ) {
                    if (el.classList.contains('group-type')) {
                        group.type = el.innerText.trim();
                    } else if (el.classList.contains('group-name')) {
                        group.name = el.innerText.trim();
                    } else if (el.tagName == "A") {
                        if (el.href.startsWith("http")) group.link = el.href;
                        else group.link = "http://tagpro-"+group.server+".koalabeast.com"+el.href;
                    } else if (el.innerText.trim().startsWith('Leader')) {
                        group.leader = el.innerText.slice(el.innerText.indexOf(":")+1);
                    } else if (el.innerText.trim().startsWith('Players')) {
                        group.players = el.innerText.slice(el.innerText.indexOf(":")+1);
                    }
                }
            }
        }

        else console.error("Couldn't get groups on "+response.context, response);

        if (pending === 0) resolve(groups);
    }
});}



function update_groups() {


    if (!(window.location.pathname === '/groups' && groups_on_groups || // If we are on the groups selection page
    window.location.pathname.match(/^\/groups\/[a-z]{8}$/) && groups_in_group || // If we are in a group
    window.location.pathname === '/games/find' && groups_on_find || // In the process of joining a game
    window.location.pathname === '/' && groups_on_home )) // If we are on the homepage
    { return; }


    // Relocate the groups container
    // Add the container to the userscript-div and make unhide that
    if (groups_list.parentElement.id == "GroPro-groups") {
        var pos =
            document.getElementById('userscript-'+position) ||
            document.getElementById('userscript-home') ||
            document.getElementById('userscript-top') ||
            (location.host.startsWith("tagpro.") && document.getElementsByClassName('header')[0]);
        if (!pos) return tagpro.helpers.displayError('Sorry, something went wrong while trying to show you the groups of all servers. Error code: Giraffe (inform /u/Wilcooo if you want me to fix it)');
        if (insertBefore) pos.insertBefore(container, pos.firstChild);
        else pos.append(container);
        pos.classList.remove('hidden');
    }

    groups_list.className = 'row groups-list';

    var groups_list_cache = GM_getValue('groups-list-cache',{});

    groups_list.innerHTML = '<div class=spinner align=center> <div class=spinner-item></div> <div class=spinner-item></div> <div class=spinner-item></div> <div class=spinner-item></div>';

    if (Date.now() - groups_list_cache.time < 65e3) groups_list.innerHTML += groups_list_cache.html;

    // Get ping and server stats for each server
    window.addEventListener('load',function(){

        servers.forEach( function(server) {
            var host = 'http://tagpro-'+server+'.koalabeast.com:80';

            var connection = io.connect(host, {transports: ["websocket"]});

            connection.on('connect',function(){
                var ping = -Date.now();
                connection.emit('stats',{},function(stats) {
                    ping += Date.now();

                    styleSheet.insertRule('.'+server+'-stats:after { content:"(ping: '+ping+', '+stats.players+' players in '+stats.games+' games)"; color:#868686; font-style:italic; font-size:small; }');
                    styleSheet.insertRule('.'+server+'-stats .spinner { display:none !important; }');
                });
            });
        });
    });


    get_groups().then(function(groups) {

        groups_list.innerHTML = '';

        for (var group of groups) {
            var group_html =
                    `<div class="col-sm-6 col-md-4">
                        <div class="group-item">
                            <div class="row">
                                <div class="col-md-12">
                                    <div class="pull-right group-type"> `+group.type+` </div>
                                    <div class="group-name ellipsis"> `+group.name+` </div>
                                </div>
                                <div class="col-xs-6">
                                    <div class="ellipsis"> Leader: `+group.leader+` </div>
                                    <div class="ellipsis"> Players: `+group.players+` </div>
                                </div>
                                <div class="col-xs-6">
                                    <a class="btn btn-primary pull-right ellipsis" href="`+group.link+`"> Join Group </a>
                                </div>
                                <div class="col-xs-12 ellipsis `+group.server+`-stats">
                                    Server: `+group.server[0].toUpperCase() + group.server.slice(1)+`
                                    <div class=spinner style="display:inline">
                                        <div class=spinner-item></div>
                                        <div class=spinner-item></div>
                                        <div class=spinner-item></div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>`;
            groups_list.innerHTML += group_html;
        }

        if (groups.flagged) {
            groups_list.innerHTML = `
                    <div class="col-sm-6 col-md-4">
                        <div class="group-item" style="height:118px; font-size:smaller; color:lightgray">
                            Sorry, your IP address has been flagged by TagPro - so the GroupsOnHome script can't yet show you the groups. No worries though, I'm working on a fix for this.
                        </div>
                    </div>`;
        } else if (groups.length === 0) {
            groups_list.innerHTML = `
                    <div class="col-sm-6 col-md-4">
                        <div class="group-item" style="height:118px">
                            <div class="row">
                                <div class="col-md-12">
                                    <div class="group-name">No public groups available. Create one!</div>
                                </div>
                            </div>
                        </div>
                    </div>`;
        }

        if (window.location.pathname !== '/groups') {
            groups_list.innerHTML +=
                `<div class="col-sm-6 col-md-4">
                     <div class="group-item">
                         <div class="row">
                             <form method="post" action="/groups/create">
                                 <div class="col-md-12">
                                     <input name="name" class="group-name" style="background:0;border:0;width:100%;height:27px" value="Your group">
                                 </div>
                                 <div class="col-md-12"><br></div>
                                 <div class="col-xs-6">
                                     <label tabindex="0" class="btn btn-default input-label ellipsis">
                                         <input tabindex="-1" type="checkbox" name="public"> Public Group
                                     </label>
                                 </div><div class="col-xs-6">
                                     <button class="btn btn-primary ellipsis pull-right" style="">Create Group</button>
                                 </div>
                             </form>
                         </div>
                     </div>
                 </div>`;
        }

        for (var label of document.getElementsByClassName('input-label')) {
            label.onkeydown = function(keydown) {
                if (keydown.code == 'Space') {
                    keydown.preventDefault();
                    keydown.target.firstElementChild.checked ^= true;
                }
                if (keydown.code == 'Enter') {
                    keydown.preventDefault();
                    keydown.target.closest('form').submit();
                }
            };
        }

        GM_setValue('groups-list-cache', {'html': groups_list.innerHTML, 'time': Date.now()});
    });


    clearTimeout(timeout);
    if (interval) timeout = setTimeout(update_groups, 1000*interval);
}


var timeout = -1,
    groups_list = document.querySelector(".groups-list") || document.createElement('div');

// Create a container for the groups
if (!groups_list.parentElement) {
    var container = document.createElement('div');
    container.id = 'GroPro-groups';
    container.className = 'container';

    container.appendChild(groups_list);
}

update_groups();


document.head.appendChild( document.createElement('style' ));
var styleSheet = document.styleSheets[ document.styleSheets.length -1 ];

styleSheet.insertRule( '.ellipsis { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }' );