The West Rankings CSV Exporter

Extract player rankings data (name, level, experience) and export to CSV

// ==UserScript==
// @name         The West Rankings CSV Exporter
// @namespace    TW-Export-Player-CSV
// @version      1.0
// @description  Extract player rankings data (name, level, experience) and export to CSV
// @author       Frozah
// @include https://*.the-west.*/game.php*
// @grant        none
// ==/UserScript==

(function (fn) {
    var script = document.createElement('script');
    script.setAttribute('type', 'application/javascript');
    script.textContent = '(' + fn + ')();';
    document.body.appendChild(script);
    document.body.removeChild(script);
})(function () {

    RankingExporter = {
        version: '1.0',
        name: 'Rankings CSV Exporter',
        author: 'Assistant',
        preferences: {
            includeAllPages: true,
            maxPages: 16
        },

        // Données collectées
        playersData: [],
        currentPage: 1,
        totalPages: 16,
        isScrapingInProgress: false,
        progressBar: null,

        // Interface utilisateur
        selectBox: null,

        // Initialisation du script
        init: function() {
            this.createSelectBox();
            this.addMenuButton();
        },

        // Création de la boîte de sélection
        createSelectBox: function() {
            var self = this;
            var listener = function(action) {
                switch(action) {
                    case 'export_current':
                        self.exportCurrentPage();
                        break;
                    case 'export_all':
                        self.exportAllPages();
                        break;
                    case 'stop_scraping':
                        self.stopScraping();
                        break;
                }
            };

            this.selectBox = new west.gui.Selectbox()
                .setWidth(200)
                .addListener(listener)
                .addItem('export_current', 'Exporter page actuelle')
                .addItem('export_all', 'Exporter toutes les pages')
                .addItem('stop_scraping', 'Arrêter le scraping');
        },

        // Ajout du bouton dans le menu
        addMenuButton: function() {
            var self = this;

            // Création d'un bouton simple (carré coloré)
            var menuButton = $('<div id="RankingExportermenu" class="menulink" title="' + this.name + '" />')
                .css({
                    'background-color': '#8B4513',
                    'width': '25px',
                    'height': '25px',
                    'cursor': 'pointer',
                    'border': '2px solid #654321',
                    'margin': '2px'
                })
                .on('mouseenter', function() {
                    $(this).css('background-color', '#A0522D');
                })
                .on('mouseleave', function() {
                    $(this).css('background-color', '#8B4513');
                })
                .click(function() {
                    self.toggleSelectbox();
                });

            var div = $('<div class="ui_menucontainer" />')
                .append(menuButton)
                .append('<div class="menucontainer_bottom" />');

            $('#ui_menubar').append(div);
        },

        // Affichage/masquage de la boîte de sélection
        toggleSelectbox: function() {
            var pos = $('div#RankingExportermenu').offset();
            pos = {
                clientX: pos.left,
                clientY: pos.top
            };
            this.selectBox.show(pos);
        },

        // Extraction des données de la page actuelle
        extractCurrentPageData: function() {
            var data = [];
            var rows = $('.ranking-experience .tbody .tw2gui_scrollpane_clipper_contentpane .row');

            rows.each(function(index) {
                var row = $(this);

                // Extraire le nom du joueur
                var playerNameCell = row.find('.exp_playername a');
                var playerName = '';
                if (playerNameCell.length > 0) {
                    playerName = playerNameCell.text().trim();
                } else {
                    // Si pas de lien, prendre le texte direct
                    playerName = row.find('.exp_playername').text().trim();
                }

                // Extraire le niveau
                var level = row.find('.exp_level').text().trim();

                // Extraire l'expérience
                var experience = row.find('.exp_exp').text().trim();

                // Extraire le rang
                var rank = row.find('.exp_rank').text().trim();

                if (playerName && level && experience && rank) {
                    data.push({
                        rank: rank,
                        name: playerName,
                        level: level,
                        experience: experience
                    });
                }
            });

            return data;
        },

        // Export de la page actuelle
        exportCurrentPage: function() {
            var data = this.extractCurrentPageData();

            if (data.length === 0) {
                new UserMessage('Aucune donnée trouvée sur cette page', UserMessage.TYPE_ERROR).show();
                return;
            }

            this.generateCSV(data, 'rankings_current_page.csv');
            new UserMessage('Export de la page actuelle terminé (' + data.length + ' joueurs)', UserMessage.TYPE_SUCCESS).show();
        },

        // Export de toutes les pages
        exportAllPages: function() {
            if (this.isScrapingInProgress) {
                new UserMessage('Scraping déjà en cours...', UserMessage.TYPE_ERROR).show();
                return;
            }

            this.isScrapingInProgress = true;
            this.playersData = [];
            this.currentPage = 1;

            // Déterminer le nombre total de pages
            this.getTotalPages();

            new UserMessage('Début du scraping de ' + this.totalPages + ' pages...', UserMessage.TYPE_HINT).show();

            // Créer une barre de progression
            this.createProgressDialog();

            // Commencer le scraping
            this.scrapePage(1);
        },

        // Déterminer le nombre total de pages
        getTotalPages: function() {
            // Méthode 1: Chercher dans la pagination
            var paginationText = $('.rl_pagebar_ranking .maxpages').text();
            if (paginationText) {
                var match = paginationText.match(/\/\s*(\d+)/);
                if (match) {
                    this.totalPages = parseInt(match[1]);
                    return;
                }
            }

            // Méthode 2: Compter les liens de pagination
            var pageLinks = $('.rl_pagebar_ranking .pagebar_page');
            if (pageLinks.length > 0) {
                var lastPage = 1;
                pageLinks.each(function() {
                    var pageNum = parseInt($(this).text());
                    if (!isNaN(pageNum) && pageNum > lastPage) {
                        lastPage = pageNum;
                    }
                });
                this.totalPages = lastPage;
                return;
            }

            // Par défaut, utiliser 16 pages
            this.totalPages = 16;
        },

        // Créer la boîte de dialogue de progression
        createProgressDialog: function() {
            var self = this;
            var content = $('<div><p>Scraping en cours...</p></div>');

            this.progressBar = new west.gui.Progressbar(0, this.totalPages);
            content.append(this.progressBar.getMainDiv());

            this.progressDialog = new west.gui.Dialog("Export en cours", content);
            this.progressDialog.addButton("Annuler", function() {
                self.stopScraping();
                self.progressDialog.hide();
            });
            this.progressDialog.show();
        },

        // Scraping d'une page spécifique
        scrapePage: function(pageNumber) {
            var self = this;

            if (!this.isScrapingInProgress || pageNumber > this.totalPages) {
                this.finalizeScraping();
                return;
            }

            // Mettre à jour la barre de progression
            if (this.progressBar) {
                this.progressBar.setValue(pageNumber - 1);
            }

            new UserMessage('Scraping de la page ' + pageNumber + '/' + this.totalPages + '...', UserMessage.TYPE_HINT).show();

            // Aller à la page
            this.goToPage(pageNumber, function() {
                setTimeout(function() {
                    // Attendre que la page soit complètement chargée
                    self.waitForPageLoad(function() {
                        var pageData = self.extractCurrentPageData();
                        self.playersData = self.playersData.concat(pageData);

                        console.log('Page ' + pageNumber + ' scrapée: ' + pageData.length + ' joueurs');

                        // Passer à la page suivante
                        setTimeout(function() {
                            self.scrapePage(pageNumber + 1);
                        }, 1500); // Délai entre les pages augmenté
                    });
                }, 1000); // Délai initial pour laisser la page se charger
            });
        },

        // Attendre que la page soit chargée
        waitForPageLoad: function(callback) {
            var self = this;
            var attempts = 0;
            var maxAttempts = 10;

            var checkLoad = function() {
                attempts++;
                var rows = $('.ranking-experience .tbody .tw2gui_scrollpane_clipper_contentpane .row');

                if (rows.length > 0 || attempts >= maxAttempts) {
                    callback();
                } else {
                    setTimeout(checkLoad, 500);
                }
            };

            checkLoad();
        },

        // Navigation vers une page spécifique (améliorée)
        goToPage: function(pageNumber, callback) {
            var self = this;

            try {
                // Méthode 1: Utiliser le champ de saisie de page
                var pageInput = $('.rl_pagebar_ranking .tw2gui_textfield input[type="text"]');
                if (pageInput.length > 0) {
                    pageInput.val(pageNumber);

                    // Déclencher les événements pour valider la saisie
                    pageInput.trigger('input');
                    pageInput.trigger('change');

                    // Simuler la touche Entrée
                    var enterEvent = jQuery.Event('keypress');
                    enterEvent.which = 13; // Code de la touche Entrée
                    enterEvent.keyCode = 13;
                    pageInput.trigger(enterEvent);

                    setTimeout(function() {
                        if (callback) callback();
                    }, 800);
                    return;
                }

                // Méthode 2: Utiliser Ajax directement (inspirée du second script)
                if (typeof Ajax !== 'undefined' && Ajax.remoteCall) {
                    Ajax.remoteCall("ranking", "get_ranking_page", {
                        page: pageNumber,
                        type: "experience"
                    }, function(response) {
                        // Attendre que la page soit mise à jour
                        setTimeout(function() {
                            if (callback) callback();
                        }, 500);
                    });
                    return;
                }

                // Méthode 3: Cliquer sur le lien de pagination
                var pageLink = $('.rl_pagebar_ranking .pagebar_page').filter(function() {
                    return $(this).text() == pageNumber;
                });

                if (pageLink.length > 0) {
                    pageLink.click();
                    setTimeout(function() {
                        if (callback) callback();
                    }, 800);
                    return;
                }

                // Si aucune méthode ne fonctionne, continuer quand même
                console.log('Impossible de naviguer vers la page ' + pageNumber);
                if (callback) callback();

            } catch (e) {
                console.error('Erreur lors de la navigation vers la page ' + pageNumber + ':', e);
                if (callback) callback();
            }
        },

        // Finalisation du scraping
        finalizeScraping: function() {
            this.isScrapingInProgress = false;

            // Fermer la boîte de dialogue de progression
            if (this.progressDialog) {
                this.progressDialog.hide();
            }

            if (this.playersData.length === 0) {
                new UserMessage('Aucune donnée collectée', UserMessage.TYPE_ERROR).show();
                return;
            }

            // Tri par rang
            this.playersData.sort(function(a, b) {
                return parseInt(a.rank) - parseInt(b.rank);
            });

            // Supprimer les doublons (au cas où)
            var uniqueData = [];
            var seenRanks = {};

            for (var i = 0; i < this.playersData.length; i++) {
                var player = this.playersData[i];
                if (!seenRanks[player.rank]) {
                    uniqueData.push(player);
                    seenRanks[player.rank] = true;
                }
            }

            this.generateCSV(uniqueData, 'rankings_all_pages.csv');
            new UserMessage('Export terminé ! ' + uniqueData.length + ' joueurs exportés', UserMessage.TYPE_SUCCESS).show();
        },

        // Arrêt du scraping
        stopScraping: function() {
            this.isScrapingInProgress = false;

            if (this.progressDialog) {
                this.progressDialog.hide();
            }

            new UserMessage('Scraping arrêté', UserMessage.TYPE_ERROR).show();
        },

        // Génération du fichier CSV
        generateCSV: function(data, filename) {
            if (data.length === 0) {
                return;
            }

            // En-têtes CSV
            var csv = 'Rang,Nom du joueur,Niveau,Expérience\n';

            // Données
            data.forEach(function(player) {
                // Échapper les guillemets et virgules
                var name = '"' + player.name.replace(/"/g, '""') + '"';
                var experience = '"' + player.experience.replace(/"/g, '""') + '"';

                csv += player.rank + ',' + name + ',' + player.level + ',' + experience + '\n';
            });

            // Téléchargement du fichier
            this.downloadCSV(csv, filename);
        },

        // Téléchargement du fichier CSV
        downloadCSV: function(csvContent, filename) {
            var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            var link = document.createElement('a');

            if (link.download !== undefined) {
                var url = URL.createObjectURL(blob);
                link.setAttribute('href', url);
                link.setAttribute('download', filename);
                link.style.visibility = 'hidden';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(url);
            }
        },

        // Vérification si on est sur la page des classements
        isOnRankingsPage: function() {
            return $('.ranking-experience').length > 0;
        }
    };

    // Initialisation une fois le document prêt
    $(document).ready(function() {
        try {
            // Attendre que les objets du jeu soient disponibles
            var initInterval = setInterval(function() {
                if (typeof west !== 'undefined' &&
                    typeof west.gui !== 'undefined' &&
                    typeof west.gui.Selectbox !== 'undefined' &&
                    typeof UserMessage !== 'undefined') {

                    clearInterval(initInterval);
                    RankingExporter.init();
                }
            }, 1000);

        } catch (e) {
            console.log('Erreur lors de l\'initialisation du script Rankings Exporter:', e);
        }
    });

    // Debug : afficher le nom du script dans la console
    console.log('Script Rankings CSV Exporter v' + RankingExporter.version + ' chargé');
});