MusicBrainz: Easy-Add Recording Alias

Inserts "Add Alias" buttons in Recording pages and auto-fills the Add Alias form.

目前為 2025-12-02 提交的版本,檢視 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         MusicBrainz: Easy-Add Recording Alias
// @namespace    http://tampermonkey.net/
// @version      2025.12.02.2
// @description  Inserts "Add Alias" buttons in Recording pages and auto-fills the Add Alias form.
// @author       peepincreepin
// @match        *://*.musicbrainz.org/recording/*
// @grant        GM_setClipboard
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // --- CONFIGURATION ---
    // The class of the table to target
    const TABLE_CLASS = "tbl";
    // The class of rows to exclude
    const EXCLUDE_CLASS = "subh";
    // Target Input ID on the destination page
    const TARGET_INPUT_ID = "id-edit-alias.name";
    // Wait 500ms after page load to ensure we overwrite MB scripts
    const OVERWRITE_DELAY_MS = 500;

    // --- MAIN LOGIC ---
    const currentUrl = window.location.href;

    // SCENARIO 1: We are on the "Add Alias" page (Destination)
    if (currentUrl.includes("/add-alias")) {
        handleAliasPage();
    }
    // SCENARIO 2: We are on the main Recording page (Source)
    else {
        handleRecordingPage();
    }

    // --- FUNCTIONS ---

    function handleRecordingPage() {
        const listTable = document.querySelector(`table.${TABLE_CLASS}`);

        if (!listTable) {
            console.log("MusicBrainz Alias Helper: No table found.");
            return;
        }

        const rows = listTable.querySelectorAll("tr");

        // We need to handle the header row separately to keep the table structure valid
        // or the columns will misalign.
        const headerRow = listTable.querySelector("thead tr");
        if(headerRow) {
             const th = document.createElement("th");
             th.innerText = "Alias Tool";
             headerRow.insertBefore(th, headerRow.firstChild);
        }

        rows.forEach(row => {
            // Exclude rows with specific class (subh) or if it's a header row in tbody
            if (row.classList.contains(EXCLUDE_CLASS) || row.closest('thead')) {
                return;
            }

            // Create the button cell
            const btnCell = document.createElement("td");
            const btn = document.createElement("button");
            btn.innerText = "Add Alias";
            btn.style.fontSize = "11px";
            btn.style.cursor = "pointer";

            // Button Logic
            btn.addEventListener("click", (e) => {
                e.preventDefault();

                // Get the existing cells (before we inserted our new one, indices might shift)
                // We inserted our new cell at index 0, so the "second td" is now index 2.
                // However, to be safe, let's query all tds and pick by current DOM order.
                const cells = row.querySelectorAll("td");

                // Note: Since we prepend a cell (btnCell), the original "second td"
                // is now the 3rd cell (index 2), assuming the row started with at least 2 cells.
                // If we grab content BEFORE appending, it's index 1.
                // Let's grab it dynamically relative to the button to be robust.

                // Logic: The button is in the first cell. The original 2nd cell is now the 3rd cell.
                // But let's stick to the prompt's logic of the "second td" of the original row data.
                // The safest way is to grab the cell at index 2 (0=button, 1=orig_1st, 2=orig_2nd).

                let targetCell = cells[2];

                // Fallback check if the table structure is simpler than expected
                if (!targetCell) targetCell = cells[1];

                if (targetCell) {
                    // 1. Capture label
                    let var_aliasname = targetCell.innerText.trim();

                    // 2. Add to clipboard
                    GM_setClipboard(var_aliasname);

                    // 3. Feedback (optional visual cue)
                    const originalText = btn.innerText;
                    btn.innerText = "Copied!";
                    setTimeout(() => btn.innerText = originalText, 1000);

                    // 4. Open new tab with data passed via URL Parameter
                    // We append ?auto_alias=VALUE to the URL
                    const baseUrl = window.location.href.split('?')[0]; // clean base URL
                    const targetUrl = `${baseUrl}/add-alias?auto_alias=${encodeURIComponent(var_aliasname)}`;
                    window.open(targetUrl, '_blank');
                } else {
                    alert("Could not find the text in the second column.");
                }
            });

            btnCell.appendChild(btn);

            // Insert at the beginning of the row (Left side)
            row.insertBefore(btnCell, row.firstChild);
        });
    }

    function handleAliasPage() {
        // Parse the URL parameters
        const urlParams = new URLSearchParams(window.location.search);
        const aliasName = urlParams.get('auto_alias');

        if (aliasName) {
            // We attach a listener to 'load'. This fires when all scripts, css, and images are done.
            window.addEventListener('load', () => {

                // We add an extra delay (setTimeout) to ensure the MusicBrainz script
                // has finished its execution stack before we run.
                setTimeout(() => {
                    const inputField = document.getElementById(TARGET_INPUT_ID);
                    if (inputField) {
                        // 1. Force the value
                        inputField.value = aliasName;

                        // 2. Trigger 'change' event in case other scripts are watching this input
                        inputField.dispatchEvent(new Event('change', { bubbles: true }));

                        // 3. Visual feedback so you know it worked
                        inputField.style.backgroundColor = "#e6fffa";
                        inputField.style.border = "2px solid #38b2ac";
                        inputField.focus();
                    }
                }, OVERWRITE_DELAY_MS);

            });
        }
    }

})();