# Request for a User Script

**URL:** https://community.metabrainz.org/t/request-for-a-user-script/778086
**Category:** MusicBrainz
**Tags:** userscripts
**Created:** [July 30, 2025, 12:58pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086 "2025-07-30T12:58:57Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [July 30, 2025, 12:58pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/1 "2025-07-30T12:58:57Z")

</div>

Hi All

There is this wonder user script to import releases to MB. Every artist and release has this beautiful pink thingie if it has a link to MB

![Schermafbeelding 2025-07-30 145459](https://community.metabrainz.org/uploads/default/original/3X/1/d/1d08a515405ac0606938500848b24aa6d2a4aa16.png)

Question: is someone willing to make a user script that shows this wonderful pink thingie with the artists and works on Second Hand Songs? I would save me so so so much time and I dont have to look everything up.

The script does not have to do anything else, just show that thingie, when the artist of work has a link to MB.

I would be grateful forever 🙂

Greets Tis

---

<div class="post-metadata">

### Author: ![sanojjonas](https://community.metabrainz.org/letter_avatar_proxy/v4/letter/s/e9c0ed/32.png) [@sanojjonas](https://community.metabrainz.org/u/sanojjonas)
#### Post date: [July 30, 2025, 4:57pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/2 "2025-07-30T16:57:52Z")

</div>

i think i need more information about what u want on what site and where exactly.

because i don’t understand what you actually want…

you are talking about an already existing userscript, which one? link it somewhere. give as much information as possible

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [July 30, 2025, 5:06pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/3 "2025-07-30T17:06:43Z")

</div>

The icons are a feature of the [MBlinks library](https://github.com/murdos/musicbrainz-userscripts/blob/master/lib/mblinks.js) and is commonly used by userscript-based importers

The site @Tiske_Tisja would like an integration for is [https://secondhandsongs.com/](https://secondhandsongs.com/)

---

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [July 31, 2025, 5:33am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/4 "2025-07-31T05:33:51Z")

</div>

Thank you Chaban, that is what I mean. Your English is better then mine 🙂

The userscript I mean is: Import Discogs releases to MusicBrainz from Murdos. That usercript shows you those pink thingies on Discogs.

@ [sanojjonas](https://community.metabrainz.org/u/sanojjonas) For me the userscript does not have to import anything. The only thing I want is to be able to see **on [https://secondhandsongs.com/](https://secondhandsongs.com/)** is which **artists** and **works** already have a Second Hand Song URL in MB.

Like this:

 ![Schermafbeelding 2025-07-30 145459](https://community.metabrainz.org/uploads/default/original/3X/d/8/d8f26a42eb4f18f21869e68e6ba9e41eb3fde0bc.png)

---

<div class="post-metadata">

### Author: ![Camaxtli](https://community.metabrainz.org/user_avatar/community.metabrainz.org/camaxtli/32/106014_2.png) [@Camaxtli](https://community.metabrainz.org/u/Camaxtli)
#### Post date: [July 31, 2025, 7:55am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/5 "2025-07-31T07:55:25Z")

</div>

That would be usefull indeed

---

<div class="post-metadata">

### Author: ![aerozol](https://community.metabrainz.org/user_avatar/community.metabrainz.org/aerozol/32/116_2.png) [@aerozol](https://community.metabrainz.org/u/aerozol)
#### Post date: [July 31, 2025, 10:08am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/6 "2025-07-31T10:08:18Z")

</div>

I looooove that feature as well!

I banged my head into chatGPT for hours trying to get one to work for rateyourmusic but [the result](https://github.com/Aerozol/metabrainz-userscripts?tab=readme-ov-file#-musicbrainz-rym-link-checker) is a bit crap quite frankly. I think it needs an expert…

+1 to someone making a this userscript work for other sites! It makes me add more Discogs links, to get those icons to pop up, that’s for sure.

---

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [July 31, 2025, 10:34am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/7 "2025-07-31T10:34:21Z")

</div>

Get in line @aerozol I was first 🤣 🤣 🤣 🤣

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [July 31, 2025, 11:26am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/8 "2025-07-31T11:26:30Z")

</div>

Here is a quick-and-dirty script I’ve whipped up with Gemini 2.5 Pro:

```javascript
// ==UserScript==
// @name SecondHandSongs to MusicBrainz Linker
// @namespace https://musicbrainz.org/user/chaban
// @version 1.3
// @tag ai-created
// @description Adds links from secondhandsongs.com to MusicBrainz entities.
// @author chaban
// @license MIT
// @match https://secondhandsongs.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// @require https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mblinks.js
// @require https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mbimportstyle.js
// @grant none
// ==/UserScript==

// prevent JQuery conflicts, see http://wiki.greasespot.net/@grant
this.$ = this.jQuery = jQuery.noConflict(true);

$(document).ready(function () {
    MBSearchItStyle();
    const mblinks = new MBLinks('SHS_MBLINKS_CACHE');

    /**
     * Cleans up a SecondHandSongs URL to its canonical form.
     * @param {string} url - The URL to clean.
     * @returns {string} The cleaned URL.
     */
    function cleanUrl(url) {
        return url.replace(/^(https:\/\/secondhandsongs\.com\/(?:artist|performance|work|release|label)\/\d+).*/, '$1');
    }

    /**
     * Maps SecondHandSongs URL paths to MusicBrainz entity types.
     * @param {string} path - The path segment from a SecondHandSongs URL.
     * @returns {string|null} The corresponding MusicBrainz entity type or null.
     */
    function getMbTypeFromPath(path) {
        const typeMap = {
            'artist': 'artist',
            'performance': 'recording',
            'work': 'work',
            'release': 'release',
            'label': 'label',
        };
        return typeMap[path] || null;
    }

    /**
     * Gathers all relevant entity links from a given context, groups them by type, and processes them in batches.
     * @param {Node} context - The DOM node to search within for links.
     */
    function addLinksToPage(context) {
        const $context = $(context || document);
        const canonicalPathRegex = /^\/(?:artist|performance|work|release|label)\/\d+\/?$/;
        const urlsToProcess = {}; // Group URLs by mb_type

        // Main entity on the page
        if (!context || context === document) {
            const pageUrl = cleanUrl(window.location.href);
            const path = pageUrl.split('/')[3];
            const pageType = getMbTypeFromPath(path);

            if (pageType) {
                if (!urlsToProcess[pageType]) {
                    urlsToProcess[pageType] = [];
                }
                urlsToProcess[pageType].push({
                    url: pageUrl,
                    mb_type: pageType,
                    insert_func: function (link) {
                        const $mbLink = $(link).css({
                            'margin-left': '8px',
                            'vertical-align': 'middle',
                        });
                        $('h1[itemprop="name"]').append($mbLink);
                    }
                });
            }
        }

        // Other entity links within the context
        $context.find('a[href*="/artist/"], a[href*="/performance/"], a[href*="/work/"], a[href*="/release/"], a[href*="/label/"]').each(function () {
            const $anchor = $(this);
            if ($anchor.data('mblinks-added')) {
                return;
            }
            $anchor.data('mblinks-added', true);

            const urlObject = new URL($anchor.attr('href'), window.location.href);

            if (!canonicalPathRegex.test(urlObject.pathname)) {
                return;
            }

            const url = cleanUrl(urlObject.href);
            const path = url.split('/')[3];
            const type = getMbTypeFromPath(path);

            if (type) {
                if (!urlsToProcess[type]) {
                    urlsToProcess[type] = [];
                }
                urlsToProcess[type].push({
                    url: url,
                    mb_type: type,
                    insert_func: function (link) {
                        const $mbLink = $(link).css({
                            'margin-left': '4px',
                            'vertical-align': 'middle',
                        });
                         const $parentSpan = $anchor.closest('span[itemprop="name"]');
                        if ($parentSpan.length) {
                            $parentSpan.after($mbLink);
                        } else {
                            $anchor.after($mbLink);
                        }
                    }
                });
            }
        });

        // Process each group of URLs with the correct entity type
        for (const type in urlsToProcess) {
            if (urlsToProcess.hasOwnProperty(type)) {
                mblinks.searchAndDisplayMbLinks(urlsToProcess[type]);
            }
        }
    }

    // Initial run on page load
    addLinksToPage();

    // Observe for dynamically loaded content
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes.length) {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        addLinksToPage(node);
                    }
                });
            }
        });
    });

    const targetNode = document.getElementById('root');
    if (targetNode) {
        observer.observe(targetNode, {
            childList: true,
            subtree: true,
        });
    }
});

```

However the performance is quite bad due to many links existing on SecondHandSongs and MBlinks.js apparently not optimized yet to query multiple URLs per API call.

@aerozol You might want to try Gemini if ChatGPT struggles. For the above I basically pointed it at the murdos repo, uploaded an example artist page and asked it to create a userscript similar to the importer but with just the linking feature.

Afterwards I only needed to instruct it to fix the icon position (supplying a screenshot) and ask for support of other entities by feeding it with the [URL clean-up code from MBS](https://github.com/metabrainz/musicbrainz-server/blob/686ccbae8e52ff9edeae3b2780d220924e667139/root/static/scripts/edit/URLCleanup.js#L5292-L5335) as reference.

---

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [July 31, 2025, 11:41am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/9 "2025-07-31T11:41:50Z")

</div>

Oww @Chaban thank you so very much. Can you please explain to me how I can install this?

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [July 31, 2025, 11:52am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/10 "2025-07-31T11:52:55Z")

</div>

Please don’t use it. It’s very rough around the edges. I’m currently trying to polish it a bit but since I don’t use SecondHandSongs there are probably many things I’m missing and it will still be catastrophic.

But if you really want to see [Creating a userscript - Violentmonkey](https://violentmonkey.github.io/guide/creating-a-userscript/#create-a-userscript-for-the-active-tab)  
Copy the code to the clipboard

![image](https://community.metabrainz.org/uploads/default/original/3X/c/0/c0e5261b0aab87d4ac51ecbe382da6038f3fb319.png)

and then paste it in the new script window overwriting the entire placeholder text and save it.

---

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [July 31, 2025, 12:09pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/11 "2025-07-31T12:09:06Z")

</div>

Hahah I will wait, thank you so much again Chaban

---

<div class="post-metadata">

### Author: ![kellnerd](https://community.metabrainz.org/user_avatar/community.metabrainz.org/kellnerd/32/66963_2.png) [@kellnerd](https://community.metabrainz.org/u/kellnerd)
#### Post date: [July 31, 2025, 1:59pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/12 "2025-07-31T13:59:48Z")

</div>

> [@chaban](#):
>
> However the performance is quite bad due to many links existing on SecondHandSongs and MBlinks.js apparently not optimized yet to query multiple URLs per API call.

A new function for batch-processing has been contributed recently, but so far it is only used by the Bandcamp importer:

> <https://github.com/murdos/musicbrainz-userscripts/pull/633/files>
>
> \- just stumbled upon the Jira thread that release relationship lookup supports b…atching now;
> \- implemented a new function to batch process multiple URLs for MusicBrainz links;
> \- adjusted the existing logic to utilize the new batch processing feature for discography pages on Bandcamp.

It should be trivial to adapt all other importers / scripts which use this feature to use the new function. If I would have had the time to import releases into MB lately, I probably would have done it myself already 😅

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [August 1, 2025, 4:27pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/13 "2025-08-01T16:27:29Z")

</div>

I gave Gemini two more nudges and now URL queries are grouped by type and batched.

@Tiske_Tisja I think you can test it now. Grab the newest version 1.3 from my [previous post](https://community.metabrainz.org/t/request-for-a-user-script/778086/8)

---

<div class="post-metadata">

### Author: ![Tiske\_Tisja](https://community.metabrainz.org/user_avatar/community.metabrainz.org/tiske_tisja/32/63405_2.png) [@Tiske\_Tisja](https://community.metabrainz.org/u/Tiske_Tisja)
#### Post date: [August 2, 2025, 5:08am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/14 "2025-08-02T05:08:16Z")

</div>

Thank you so much Chaban!!!

Fantastic !!! I’m so so happy 🙂

Look how BEAUTIFULLLLLLLL

 ![Schermafbeelding 2025-08-02 100656](https://community.metabrainz.org/uploads/default/original/3X/1/7/1765d01f93ec8abe93732e36b8dd15c3b431dfac.png)

---

<div class="post-metadata">

### Author: ![aerozol](https://community.metabrainz.org/user_avatar/community.metabrainz.org/aerozol/32/116_2.png) [@aerozol](https://community.metabrainz.org/u/aerozol)
#### Post date: [August 7, 2025, 11:38pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/15 "2025-08-07T23:38:31Z")

</div>

I’ve bashed my head against a wall with Gemini… It very quickly got the following script right, which checks for artist backlinks (for instance [on VA albums](https://rateyourmusic.com/release/album/various-artists/outlier-festival-2022-new-electronic-music-from-aotearoa/)):

```auto
// ==UserScript==
// @name RateYourMusic to MusicBrainz Linker
// @namespace https://musicbrainz.org/user/yourusername
// @version 1.0
// @description Adds links from RateYourMusic to MusicBrainz entities.
// @author Gemini
// @license MIT
// @match https://rateyourmusic.com/*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// @require https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mblinks.js
// @require https://raw.githubusercontent.com/murdos/musicbrainz-userscripts/master/lib/mbimportstyle.js
// @grant none
// ==/UserScript==

// Prevent JQuery conflicts
this.$ = this.jQuery = jQuery.noConflict(true);

$(document).ready(function() {
    MBSearchItStyle();
    const mblinks = new MBLinks('RYM_MBLINKS_CACHE');

    /**
     * Cleans up a Rate Your Music URL to its canonical form.
     * @param {string} url - The URL to clean.
     * @returns {string} The cleaned URL.
     */
    function cleanUrl(url) {
        return url.replace(/^(https:\/\/rateyourmusic\.com\/(?:artist|release|label)\/[^/]+).*/, '$1');
    }

    /**
     * Maps Rate Your Music URL paths to MusicBrainz entity types.
     * @param {string} path - The path segment from a RYM URL.
     * @returns {string|null} The corresponding MusicBrainz entity type or null.
     */
    function getMbTypeFromPath(path) {
        const typeMap = {
            'artist': 'artist',
            'release': 'release',
            'label': 'label',
        };
        return typeMap[path] || null;
    }

    /**
     * Gathers all relevant entity links from a given context, groups them by type, and processes them in batches.
     * @param {Node} context - The DOM node to search within for links.
     */
    function addLinksToPage(context) {
        const $context = $(context || document);
        const canonicalPathRegex = /^\/(?:artist|release|label)\/.+/;
        const urlsToProcess = {};

        // Main entity on the page
        if (!context || context === document) {
            const pageUrl = cleanUrl(window.location.href);
            const path = pageUrl.split('/')[3];
            const pageType = getMbTypeFromPath(path);

            if (pageType) {
                if (!urlsToProcess[pageType]) {
                    urlsToProcess[pageType] = [];
                }
                urlsToProcess[pageType].push({
                    url: pageUrl,
                    mb_type: pageType,
                    insert_func: function(link) {
                        const $mbLink = $(link).css({
                            'margin-left': '8px',
                            'vertical-align': 'middle',
                        });
                        // Target the main page title for link insertion
                        const $titleElement = $('h1.artist_name_hdr, h1.release_title_hdr, h1.label_title_hdr').first();
                        if ($titleElement.length) {
                            $titleElement.append($mbLink);
                        }
                    }
                });
            }
        }

        // Other entity links within the context (e.g., links in lists or tracklists)
        $context.find('a[href*="/artist/"], a[href*="/release/"], a[href*="/label/"]').each(function() {
            const $anchor = $(this);
            if ($anchor.data('mblinks-added')) {
                return;
            }
            $anchor.data('mblinks-added', true);

            const urlObject = new URL($anchor.attr('href'), window.location.href);

            if (!canonicalPathRegex.test(urlObject.pathname)) {
                return;
            }

            const url = cleanUrl(urlObject.href);
            const path = url.split('/')[3];
            const type = getMbTypeFromPath(path);

            if (type) {
                if (!urlsToProcess[type]) {
                    urlsToProcess[type] = [];
                }
                urlsToProcess[type].push({
                    url: url,
                    mb_type: type,
                    insert_func: function(link) {
                        const $mbLink = $(link).css({
                            'margin-left': '4px',
                            'vertical-align': 'middle',
                        });
                        // Insert the link after the anchor element
                        $anchor.after($mbLink);
                    }
                });
            }
        });

        // Process each group of URLs with the correct entity type
        for (const type in urlsToProcess) {
            if (urlsToProcess.hasOwnProperty(type)) {
                mblinks.searchAndDisplayMbLinks(urlsToProcess[type]);
            }
        }
    }

    // Initial run on page load
    addLinksToPage();

    // Observe for dynamically loaded content, as RYM pages can load content asynchronously
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes.length) {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        addLinksToPage(node);
                    }
                });
            }
        });
    });

    const targetNode = document.body;
    if (targetNode) {
        observer.observe(targetNode, {
            childList: true,
            subtree: true,
        });
    }
});

```

But we are at something like v70 trying to get something to work for RYM artist pages/releases (to match to MB release groups)!

I recently got side tracked arguing with Gemini about why it keeps adding “Final” to the script names when it knows damn well it’s doubtful that v71 is suddenly going to work\* 😅

Maybe you are better at giving prompts @chaban? Teach me your ways…

I am also curious, what did you mean by “uploaded an example artist page”? And “pointed it at the murdos repo”? I have been feeding it URL’s but I’m unclear how much it scrapes/takes from them

\*this is a joke btw peeps, I’m aware that LLM doesn’t “know” anything

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [August 8, 2025, 10:06pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/16 "2025-08-08T22:06:56Z")

</div>

> [@aerozol](#):
>
> I am also curious, what did you mean by “uploaded an example artist page”? And “pointed it at the murdos repo”? I have been feeding it URL’s but I’m unclear how much it scrapes/takes from them

I meant the feature to import a whole GitHub repo (“Code importieren”) or directory:

 ![image](https://community.metabrainz.org/uploads/default/original/3X/7/7/77e09b79d557532edda6933ee1f8c328946d9770.png)

 ![image](https://community.metabrainz.org/uploads/default/original/3X/1/6/16179bd28a09f79eb60f2ec66bb5b4addbf394fc.png)

But, alas, it seems to be an exclusive of the “AI Pro” Plan.

> **How to get Google AI Pro for free**
>
> There are ways to get it for free, for example by being “[invited](https://one.google.com/referral/terms-and-conditions/sender?storefront=%2Faipremium%2Finvite&g1_landing_page=0&utm_source=gemini&utm_medium=web&utm_campaign=invite_friends)” from a subscriber  
> It works for up to 3 people who can then use it for free up to 4 months:
> 
> ![image](https://community.metabrainz.org/uploads/default/original/3X/a/0/a09f800d111991b9f61d8de9a78b097d68733985.png)
> 
> - Buying a recent [pixel phone](https://one.google.com/offer/terms-and-conditions/pixel9pro&profold?g1_landing_page=0)
> - Some [Chromebooks](https://www.google.com/intl/de_de/chromebook/perks/)
> - Being a [student](https://gemini.google/students/)

By “uploaded an example artist page” I meant to save the page and upload it as a single HTML file. Gemini can’t directly access many pages presumably because lots of sites are blocking “AI” bots nowadays.

> [@aerozol](#):
>
> Maybe you are better at giving prompts @chaban? Teach me your ways…

I’m not sure I can actually teach you how to use it. I’m still learning and experimenting myself 🙂

This is the chat I had with Gemini to create the SecondHandSongs script:  
`https://g.co/gemini/share/d2c18a2c022b`

---

<div class="post-metadata">

### Author: ![aerozol](https://community.metabrainz.org/user_avatar/community.metabrainz.org/aerozol/32/116_2.png) [@aerozol](https://community.metabrainz.org/u/aerozol)
#### Post date: [August 9, 2025, 5:32am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/17 "2025-08-09T05:32:29Z")

</div>

Thanks @chaban! That is very useful.

Looking at your chat log it also confirms that I struggle a bit because I can’t help Gemini along, since I can’t spot weird or obviously incorrect code.

But uploading website files has already been helpful! Maybe this will give me the energy to give RYM releases another go this weekend.

---

<div class="post-metadata">

### Author: ![tigerman325](https://community.metabrainz.org/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tigerman325](https://community.metabrainz.org/u/tigerman325)
#### Post date: [July 25, 2026, 9:21pm UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/18 "2026-07-25T21:21:29Z")

</div>

If possible: A script that can change work credits from the release edit relationships page. For example, I’m editing a jazz release that is 100% instrumental. All the works have “writer” instead of “composer”. It’d be awesome if I could just mark all writers on highlighted works and change them from “writer” to “composer” or without having to do each one by one. Other examples when some editors use “composer” when it should have been “written by”, so the opposite. Common on many pop releases, etc.

---

<div class="post-metadata">

### Author: ![chaban](https://community.metabrainz.org/user_avatar/community.metabrainz.org/chaban/32/111349_2.png) [@chaban](https://community.metabrainz.org/u/chaban)
#### Post date: [July 26, 2026, 7:32am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/19 "2026-07-26T07:32:29Z")

</div>

Sounds like a job for [Group Therapy](https://github.com/majkinetor/musicbrainz-userscripts/blob/main/userscripts/group_therapy/README.md). Maybe it can already do this, haven’t used it much yet.

---

<div class="post-metadata">

### Author: ![majkinetor](https://community.metabrainz.org/user_avatar/community.metabrainz.org/majkinetor/32/2380_2.png) [@majkinetor](https://community.metabrainz.org/u/majkinetor)
#### Post date: [July 26, 2026, 9:55am UTC](https://community.metabrainz.org/t/request-for-a-user-script/778086/20 "2026-07-26T09:55:52Z")

</div>

It can in convoluted way, not as a single action. I wanted this myself for the very same reason @tigerman325 requested.

Created issue for it: [Option to replace role · Issue #470 · majkinetor/musicbrainz-userscripts · GitHub](https://github.com/majkinetor/musicbrainz-userscripts/issues/470)

[Next page](https://community.metabrainz.org/t/request-for-a-user-script/778086.md?page=2)
