OpenRouter Activity Exporter

Export OpenRouter activity data to JSON

Versión del día 06/10/2024. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

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

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         OpenRouter Activity Exporter
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Export OpenRouter activity data to JSON
// @author       Romboter
// @match        https://openrouter.ai/activity*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @license GNU GPLv3
// ==/UserScript==
/* jshint esversion: 8 */

(function() {
    'use strict';

    let activityData = [];
    let currentPage = 1;
    const DEBUG = false; // Set to false to minimize logs in production
    const MAX_RETRIES = 3;

    // Create a floating button
    const button = document.createElement('button');
    button.innerHTML = 'Export Activity';
    button.id = 'orp-export-activity-button';
    document.body.appendChild(button);

    // Style the button
    GM_addStyle(`#orp-export-activity-button {
        position: fixed;
        bottom: 20px;
        right: 20px;
        padding: 10px 20px;
        background-color: #007bff;
        color: white;
        border: none;
        border-radius: 5px;
        cursor: pointer;
        z-index: 1000;
    }
    #orp-export-activity-button:hover {
        background-color: #0056b3;
    }`);

    // Attach click event to the button
    button.addEventListener('click', function() {
        button.disabled = true;
        button.innerHTML = 'Loading...';
        fetchActivity(currentPage);
    });

    function log(...args) {
        if (DEBUG) {
            console.log(...args);
        }
    }

    function handleError(message) {
        alert(`Error: ${message}`);
        button.disabled = false;
        button.innerHTML = 'Export Activity';
    }

    async function retryFetch(url, options, retries = MAX_RETRIES) {
        for (let i = 0; i < retries; i++) {
            try {
                const response = await fetch(url, options);
                if (response.ok) {
                    return response;
                }
            } catch (e) {
                log(`Fetch attempt ${i + 1} failed:`, e);
            }
        }
        throw new Error('Maximum retries reached for fetching activity data.');
    }

    function extractData(responseText) {
        const data = {
            transactions: null,
            appInfo: null,
            pagination: null
        };

        // Extract transactions array
        const transactionsRegex = /"transactions":\s*(\[[\s\S]*?\])\s*\]/;
        const transactionsMatch = responseText.match(transactionsRegex);

        if (transactionsMatch) {
            const individualTransactionRegex = /\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/g;
            const individualTransactions = transactionsMatch[1].match(individualTransactionRegex);
            if (individualTransactions) {
                data.transactions = individualTransactions.map(transaction => {
                    try {
                        const parsedTransaction = JSON.parse(transaction);
                        // Filter out pagination object if mistakenly included
                        if (parsedTransaction.page !== undefined && parsedTransaction.hasNextPage !== undefined) {
                            return null;
                        }
                        return parsedTransaction;
                    } catch (parseError) {
                        log('Error parsing individual transaction:', parseError);
                        return null;
                    }
                }).filter(Boolean);
            }

            if (!data.transactions || data.transactions.length === 0) {
                log('Failed to parse any transactions');
            }
        } else {
            log('No transactions match found');
        }

        // Extract pagination info
        const paginationRegex = /"page":\s*(\d+),\s*"hasNextPage":\s*(true|false)/;
        const paginationMatch = responseText.match(paginationRegex);

        if (paginationMatch) {
            data.pagination = {
                page: parseInt(paginationMatch[1]),
                hasNextPage: paginationMatch[2] === 'true'
            };
        } else {
            log('No pagination match found');
        }

        return data;
    }

    async function fetchActivity(page) {
        try {
            log(`Fetching activity for page: ${page}`);
            const url = `https://openrouter.ai/activity?page=${page}`;
            const options = {
                "credentials": "include",
                "headers": {
                    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0",
                    "Accept": "*/*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "RSC": "1",
                    "Next-Url": "/activity",
                    "Priority": "u=0"
                },
                "referrer": "https://openrouter.ai/activity",
                "method": "GET",
                "mode": "cors"
            };

            const response = await retryFetch(url, options);
            const responseText = await response.text();

            if (responseText.startsWith("<!DOCTYPE html>")) {
                handleError("Received HTML instead of JSON. Possible login issue.");
                return;
            }

            const extractedData = extractData(responseText);

            if (extractedData.transactions && Array.isArray(extractedData.transactions)) {
                activityData.push(...extractedData.transactions);
                log(`Added ${extractedData.transactions.length} transactions. Total transactions: ${activityData.length}`);
            } else {
                log('No valid transactions data found in response.');
            }

            if (extractedData.pagination && extractedData.pagination.hasNextPage) {
                log('Next page found, fetching next page...');
                button.innerHTML = `Loading... (Page ${page})`;
                fetchActivity(extractedData.pagination.page + 1);
            } else {
                log('No more pages, downloading activity data...');
                downloadActivityData();
            }
        } catch (e) {
            handleError("Error fetching activity data: " + e.message);
        }
    }

    function downloadActivityData() {
        log('Downloading activity data. Total transactions:', activityData.length);
        const blob = new Blob([JSON.stringify(activityData, null, 2)], { type: "application/json" });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = 'activity_transactions.json';
        a.click();
        URL.revokeObjectURL(url);
        button.disabled = false;
        button.innerHTML = 'Export Activity';
    }
})();