Click buttons across tabs

Clicks specified buttons across tabs using the BroadcastChannel API.

Versione datata 10/06/2025. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name        Click buttons across tabs
// @namespace   https://musicbrainz.org/user/chaban
// @version     1.0
// @tag         ai-created
// @description Clicks specified buttons across tabs using the BroadcastChannel API.
// @author      chaban
// @license     MIT
// @match       *://*.musicbrainz.org/*
// @match       *://magicisrc.kepstin.ca/*
// @match       *://magicisrc-beta.kepstin.ca/*
// @grant       GM.info
// @grant       GM_registerMenuCommand
// ==/UserScript==

(function () {
    'use strict';
    /**
     * @typedef {Object} SiteConfig
     * @property {string|string[]} hostnames - A single hostname string or an array of hostname strings.
     * @property {string|string[]} paths - A single path string or an array of path strings (can be partial matches).
     * @property {string} channelName - The name of the BroadcastChannel to use for this site.
     * @property {string} messageTrigger - The message data that triggers the button click.
     * @property {string} buttonSelector - The CSS selector for the button to be clicked.
     * @property {string} menuCommandName - The name to display in the Tampermonkey/Greasemonkey menu.
     */

    /**
     * Configuration for different websites and their button click settings.
     * @type {SiteConfig[]}
     */
    const siteConfigurations = [
        {
            hostnames: 'musicbrainz.org',
            paths: ['/edit', '/add-cover-art'],
            channelName: 'mb_edit_channel',
            messageTrigger: 'submit-edit',
            buttonSelector: 'button.submit.positive[type="submit"]',
            menuCommandName: 'MusicBrainz: Submit Edit (All Tabs)'
        },

        {
            hostnames: ['magicisrc.kepstin.ca','magicisrc-beta.kepstin.ca'],
            paths: ['/'],
            channelName: 'magicisrc_submit_channel',
            messageTrigger: 'submit-isrcs',
            buttonSelector: '[onclick^="doSubmitISRCs"]',
            menuCommandName: 'MagicISRC: Submit ISRCs (All Tabs)'
        }
    ];

    const scriptName = GM.info.script.name;

    /**
     * Sends a message to the specified BroadcastChannel.
     * @param {string} channelName
     * @param {string} message
     */
    function sendMessageToChannel(channelName, message) {
        try {
            new BroadcastChannel(channelName).postMessage(message);
            console.log(`[${scriptName}] Sent message "${message}" to channel "${channelName}".`);
        } catch (error) {
            console.error(`[${scriptName}] Error sending message to channel "${channelName}":`, error);
        }
    }

    /**
     * Initializes the BroadcastChannel listener for the current site if a match is found.
     * Also registers a menu command if `GM_registerMenuCommand` is available.
     */
    function initializeBroadcastChannelListener() {
        const currentHostname = location.hostname;
        const currentPathname = location.pathname;

        for (const config of siteConfigurations) {
            const hostnames = Array.isArray(config.hostnames) ? config.hostnames : [config.hostnames];
            const paths = Array.isArray(config.paths) ? config.paths : [config.paths];

            const hostnameMatches = hostnames.some(hostname => currentHostname.endsWith(hostname));
            const pathMatches = paths.some(path => currentPathname.includes(path));

            if (hostnameMatches && pathMatches) {
                try {
                    const channel = new BroadcastChannel(config.channelName);
                    channel.addEventListener('message', (event) => {
                        if (event.data === config.messageTrigger) {
                            const btn = document.querySelector(config.buttonSelector);
                            if (btn) {
                                btn.click();
                                console.log(`[${scriptName}][${scriptName}] Button clicked for selector "${config.buttonSelector}" on channel "${config.channelName}".`);
                            } else {
                                console.warn(`[${scriptName}] Button with selector "${config.buttonSelector}" not found.`);
                            }
                        }
                    });
                    console.log(`[${scriptName}] Listener active for channel "${config.channelName}".`);
                } catch (error) {
                    console.error(`[${scriptName}] Error initializing BroadcastChannel for "${config.channelName}":`, error);
                }

                if (typeof GM_registerMenuCommand !== 'undefined' && config.menuCommandName) {
                    GM_registerMenuCommand(config.menuCommandName, () => {
                        sendMessageToChannel(config.channelName, config.messageTrigger);
                    });
                    console.log(`[${scriptName}] Registered menu command "${config.menuCommandName}".`);
                } else {
                   console.warn(`[${scriptName}] Couldn't register menu command "${config.menuCommandName}".`)
                }

                // Only activate one listener and register one command per tab for the first matching configuration
                return;
            }
        }
    }

    initializeBroadcastChannelListener();
})();