StigNygaard / Stigs_Art_Grabr

Stig's Art Grabr is a userscript for grabbing high resolution album cover-art from various sites - Can also be used as a bookmarklet/favelet.
MIT License
14 stars 3 forks source link

Retrieving the Actually Original iTunes Artwork by Modifying URL with Regex #9

Closed daoxi closed 7 months ago

daoxi commented 2 years ago

The script on Greasy Fork was really useful, but it has just one issue, it retrieves the converted artwork instead of the original artwork.

For example:

For the following Apple Music page: https://music.apple.com/us/album/the-grenade-sessions-ep/416696996

Stig's Art Grabr gives URL: https://is2-ssl.mzstatic.com/image/thumb/Features124/v4/dd/8a/24/dd8a2401-492c-77b3-b13c-b6d51f711527/dj.wkeljoft.jpg/999999x999999bb-100.jpg (Note that "999999x999999bb-100.jpg" is a converted image instead of the original image, the lossy conversion unnecessarily increase the file size, and also reduces the actual quality of image (due to jpg's lossy conversion), which are less than ideal.)

And the original image (without conversion) is at the following URL: https://a1.mzstatic.com/us/r1000/0/Features124/v4/dd/8a/24/dd8a2401-492c-77b3-b13c-b6d51f711527/dj.wkeljoft.jpg

As you can see, to convert the URL to retrieve the original image:

  1. Replace everything before (and including) "/image/thumb/" with "https://a1.mzstatic.com/us/r1000/0/"
  2. Remove everything after (and including) the last "/" (which is right after the first ".jpg" or ".png" string).
  3. Go to the resulted new URL

I suppose you could use regex for the operations above. To be more consistent, you could also use "a1.mzstatic.com" when the original url uses "is1-ssl.mzstatic.com", "a2.mzstatic.com" when the original url uses "is2-ssl.mzstatic.com", etc. (the number tops at 5).

This change can allow users to always download the original image without the unnecessary lossy conversion.

StigNygaard commented 2 years ago

Thanks @daoxi . I wasn't aware of that. I will give it a look :-)

daoxi commented 2 years ago

While this is being worked on, I built a quick bookmarklet tool to do the URL conversion, you can find it at the following repo: https://github.com/daoxi/itunes-image-link-converter

StigNygaard commented 2 years ago

@daoxi, thanks. Idea/info not forgotten, I just haven't really had time to look at it, and probably wont the for next couple of weeks either. But I'll get to it some day ;-)

StigNygaard commented 1 year ago

Hi @daoxi Just want to tell I haven't forgotten this. I just doesn't have much time or energy for work with my hobby projects at the moment.

daoxi commented 1 year ago

Hi @daoxi Just want to tell I haven't forgotten this. I just doesn't have much time or energy for work with my hobby projects at the moment.

Hi @StigNygaard, no worries and thanks a lot for following me up on this, just kindly @me once you've taken care of it (if that'd be convenient for you), please don't feel pressured to implement the fix.

tyhallcsu commented 8 months ago

Hi @daoxi* Just want to tell I haven't forgotten this. I just doesn't have much time or energy for work with my hobby projects at the moment.

Hi @StigNygaard , no worries and thanks a lot for following me up on this, just kindly @me once you've taken care of it (if that'd be convenient for you), please don't feel pressured to implement the fix.

I wrote a bad patch, add to the bottom of your script:

function FIX_SPOTIFY_IMAGE(){
    console.log("RUNNING FIX_SPOTIFY_IMAGE");
    function convertSpecificImageUrl4(url) {
        console.log("CONVERT: " + url);
    const regex = /https:\/\/is(\d+)-ssl\.mzstatic\.com\/image\/thumb\/Music(\d+)\/v4\/(.+\/.+)\.jpg\/999999x999999bb-100\.jpg/;
    let match = url.match(regex);
        console.log("match?:" + match);

    if (match) {
        console.log("MATCH");
        console.log(match);
        let subdomainIndex = match[1];
        console.log("subdomainIndex: " + subdomainIndex);
        let musicFolder = match[2];
        console.log("musicFolder: " + subdomainIndex);
        let artworkPath = match[3];
        console.log("artworkPath: " + subdomainIndex);
        let newUrl = `https://a${subdomainIndex}.mzstatic.com/us/r1000/063/Music${musicFolder}/v4/${artworkPath}.jpg`;
    }

    return url;
}

function convertSpecificImageUrl(url) {
    // Pattern matching for specific type of URL
    const regex = /https:\/\/is(\d+)-ssl\.mzstatic\.com\/image\/thumb\/Music(\d+)\/v4\/(.+\/.+)\.jpg\/999999x999999bb-100\.jpg/;
    let match = url.match(regex);

    if (match) {
        let subdomainIndex = match[1];
        let musicFolder = match[2];
        let artworkPath = match[3];

        // Construct new URL
        let newUrl = `https://a${subdomainIndex}.mzstatic.com/us/r1000/063/Music${musicFolder}/v4/${artworkPath}.jpg`;
        return newUrl;
    }

    return url; // Return original URL if no match
}

function findAndReplaceImages() {
    console.log("FINDING...");
    const images = document.querySelectorAll("img");
    console.log("imaged" + images);

    images.forEach(img => {
        let currentSrc = img.src;
        console.log("currentSrc: " + currentSrc);

        // Skip if the image has already been processed
        if (img.dataset.artProcessed) return;

        let newSrc = convertSpecificImageUrl(currentSrc);
        console.log("newSrc: " + newSrc);

        if (newSrc !== currentSrc) {
            img.src = newSrc;
            img.dataset.artProcessed = "true"; // Mark the image as processed
            img.style.border = "2px solid green !important"; // Optional: Visual cue that image has been replaced
        }
    });
}

// Call this function to perform the replacement
findAndReplaceImages();

}

// Add the automatic execution for Apple Music at the end of your script
if (window.location.hostname.includes("music.apple.com")) {
    window.addEventListener('load', function() {
        runGrabr();
        FIX_SPOTIFY_IMAGE();
    });
}

This is not optimized, but it seems to work.

Here is the full script I have:

// ==UserScript==
// @name        Stig's Art Grabr (Original)
// @namespace   dk.rockland.userscript.misc.artgrab
// @description Grabbing big high resolution album cover-art from various sites
// @version     2021.05.09.0
// @author      Stig Nygaard, https://www.rockland.dk
// @homepageURL https://www.rockland.dk/userscript/misc/artgrab/
// @supportURL  https://www.rockland.dk/userscript/misc/artgrab/
// @match       *://*.allmusic.com/*
// @match       *://*.bandcamp.com/*
// @match       *://*.music.apple.com/*
// @match       *://*.itunes.apple.com/*
// @match       *://*.musicdiner.com/*
// @match       *://*.fnd.io/*
// @match       *://labs.stephenou.com/itunes/*
// @match       *://*.last.fm/*
// @match       *://*.lastfm.de/*
// @match       *://*.lastfm.es/*
// @match       *://*.lastfm.fr/*
// @match       *://*.lastfm.it/*
// @match       *://*.lastfm.ja/*
// @match       *://*.lastfm.pl/*
// @match       *://*.lastfm.pt/*
// @match       *://*.lastfm.ru/*
// @match       *://*.lastfm.sv/*
// @match       *://*.lastfm.tr/*
// @match       *://*.lastfm.zh/*
// @match       *://*.musicbrainz.org/*
// @match       *://*.soundcloud.com/*
// @match       *://play.google.com/*
// @match       *://*.deezer.com/*
// @match       *://*.qobuz.com/*
// @match       *://*.trackitdown.net/*
// @match       *://*.45cat.com/*
// @match       *://*.amazon.com/*
// @match       *://*.amazon.co.uk/*
// @match       *://*.amazon.ca/*
// @match       *://*.amazon.co.jp/*
// @match       *://*.amazon.com.au/*
// @match       *://*.amazon.com.br/*
// @match       *://*.amazon.com.mx/*
// @match       *://*.amazon.com.sa/*
// @match       *://*.amazon.cn/*
// @match       *://*.amazon.de/*
// @match       *://*.amazon.es/*
// @match       *://*.amazon.fr/*
// @match       *://*.amazon.in/*
// @match       *://*.amazon.it/*
// @match       *://*.amazon.nl/*
// @match       *://*.amazon.pk/*
// @match       *://*.cdbaby.com/*
// @match       *://*.jamendo.com/*
// @match       *://*.magnatune.com/*
// @match       *://open.spotify.com/*
// @grant       GM_registerMenuCommand
// @grant       GM.registerMenuCommand
// @require     https://greasyfork.org/scripts/34527/code/GMCommonAPI.js?version=237846
// @noframes
// @downloadURL https://update.greasyfork.org/scripts/20771/Stig%27s%20Art%20Grabr.user.js
// @updateURL https://update.greasyfork.org/scripts/20771/Stig%27s%20Art%20Grabr.meta.js
// ==/UserScript==

/*
 *      Stig's Art Grabr is an userscript and/or bookmarklet for grabbing big high resolution
 *      album cover-art from various sites.
 *
 *      https://greasyfork.org/scripts/20771-stig-s-art-grabr
 *      https://github.com/StigNygaard/Stigs_Art_Grabr
 *
 *      Partly based on tips at http://wiki.musicbrainz.org/User:Nikki/CAA and on itunes tip
 *      from MusicBrainz/GitHub/GreasyFork user jesus2099 who has made a lot of userscripts
 *      (especially for MusicBrainz users): https://greasyfork.org/users/2206-jesus2099
 *
 *      To run this script as a bookmarklet (running latest GreasyFork hosted version), use:
 *      javascript:(function(){document.body.appendChild(document.createElement("script")).src="https://greasyfork.org/scripts/20771/code/StigsArtGrabr.js?t="+Date.now();}())
 *
 *      NOTICE:
 *      1)  On iTunes, with most browsers Stig's Art Grabr will only work when used as a
 *          userscript, and NOT when used as a bookmarklet (CSP restriction).
 *      2)  In Firefox Art Grabr used to make script commands available via page contextmenu, however from Firefox 85 support for this is officially unavailable.
 *          Instead GM4.11 introduces native script commands menus, very similar to how it works in GM3.x and in Tampermonkey. If however you miss the commands in page
 *          context menu, you can (at least for a while) add back support for this in Firefox by going to about:config and set item dom.menuitem.enabled to true.
 */

// CHANGELOG - The most important updates/versions:
let changelog = [
    {version: '2021.05.09.0', description: 'Generally substitute found ".webp" files with similar named ".jpg" files (assumed available as "fallback"). This currently affects and works for Apple Music/iTunes and Last.FM.'},
    {version: '2021.01.29.0', description: 'Support for the new native menus (GM.registerMenuCommand) in Greasemonkey 4.11.'},
    {version: '2020.12.28.0', description: 'Yet another iTunes/Apple Music fix. Musicbrainz changelog appended to pages fix.'},
    {version: '2020.07.02.0', description: 'Another iTunes/Apple Music fix.'},
    {version: '2020.05.30.1', description: 'Adding partial support for open.spotify.com. On album-pages (might not work on all playlists) it can typically replace 232X232 or 464x464 with 640x640pixels cover art. Thanks to kopytko95 for tip making this possible.'},
    {version: '2020.04.25.0', description: 'iTunes / Apple Music fix for updated site.'},
    {version: '2019.11.03.0', description: 'Last.FM fix. Mouseover and right-click should work again now.'},
    {version: '2019.10.26.0', description: 'Last.FM partial fix. Now again able to find fullsize images. But mouseover with dimensions might not show and sometimes image is "protected" behind a layer.'},
    {version: '2018.02.10.0', description: 'Adding support for Deezer, Qobuz and Trackitdown (All tested on public pages only). Big thanks to Anton Fedorov for tips making this possible.'},
    {version: '2016.06.20.0', description: '1st official release version.'}
];

function runGrabr() {
    let DEBUG = false;
    let log = function(s) {
        if (DEBUG && window.console) {
            window.console.log(s);
        }
    };
    // [ page pattern, search for img patterns, replace this, with this ]
    let a = [[/45cat\./, /-s\.jpg/i, /-s\.jpg/gi, ".jpg"],
        [/45cat\./, /-s\.png/i, /-s\.png/gi, ".png"],
        [/allmusic\./, /\/JPG_\d{3}\//i, /\/JPG_\d{3}\//gi, "/JPG_1080/"],
        [/amazon\./, /\._[A-Z]{2}\d{3}_[\w_,-]*\.jpg/i, /\._[A-Z]{2}\d{3}_[\w_,-]*\.jpg/gi, ".jpg"],
        [/amazon\./, /\._[A-Z]{2}\d{3}_[\w_,-]*\.png/i, /\._[A-Z]{2}\d{3}_[\w_,-]*\.png/gi, ".png"],
        [/bandcamp\./, /_\d{1,2}\.jpg/i, /_\d{1,2}\.jpg/gi, "_0.jpg"],
        [/bandcamp\./, /_\d{1,2}\.png/i, /_\d{1,2}\.png/gi, "_0.png"],
        [/cdbaby\./, /cdbaby\.name\/.*_small\.[jpgn]{3}/i, /_small\./gi, "."],
        [/cdbaby\./, /cdbaby\.name\/.*\.jpg/i, /\.jpg/gi, "_large.jpg"],
        [/cdbaby\./, /cdbaby\.name\/.*\.png/i, /\.png/gi, "_large.png"],
        [/deezer\./, /images\/\w{5,9}\/.*\.[jpng]{3}/i, /\/\d{2,3}x\d{2,3}-0{6}-\d{1,2}-0-0\.[jpng]{3}/gi, "/1400x1400-000000-0-0-0.png"],
        [/fnd\.io/, /\/\d{2,}x\d{2,}bb/i, /\/\d{2,}x\d{2,}bb/gi, "/999999x999999bb-100"],
        [/(music|itunes)\.apple\./, /\/\d+x\d+[a-z]*-\d+\.jpe?g$/i, /\/\d+x\d+[a-z]*-\d+\.jpe?g$/i, "/999999x999999bb-100.jpg"], // fix 2020-07-02 new image naming scheme
        [/(music|itunes)\.apple\./, /\/\d+x\d+bb\.jpe?g$/i, /\/\d+x\d+bb\.jpe?g$/i, "/999999x999999bb-100.jpg"], // fix 2020-04-25
        [/(music|itunes)\.apple\./, /\/\d+x\d+[a-z]*-\d+\.webp$/i, /\/\d+x\d+[a-z]*-\d+\.webp$/i, "/999999x999999bb-100.webp"], // fix 2020-12-28 webp
        [/(music|itunes)\.apple\./, /\/\d+x\d+bb\.webp$/i, /\/\d+x\d+bb\.webp$/i, "/999999x999999bb-100.webp"], // fix 2020-12-28 webp
        [/jamendo\./, /1\.\d00\.jpg/i, /1\.\d00\.jpg/gi, "1.0.jpg"],
        [/jamendo\./, /1\.\d00\.png/i, /1\.\d00\.png/gi, "1.0.png"],
        [/labs\.stephenou\.com/, /\/\d{2,3}x\d{2,3}bb/i, /\/\d{2,3}x\d{2,3}bb/gi, "/999999x999999bb-100"],
        // [/last(fm)?\.[a-z]{2,3}/, /\.lst\.fm\/i\/u\/[a-zA-Z]*\d{2,}\w*\//i, /\.lst\.fm\/i\/u\/[a-z]*\d{2,}\w*\//gi, ".lst.fm/i/u/"],
        // [/last(fm)?\.[a-z]{2,3}/, /\.akamaized\.net\/i\/u\/[a-zA-Z]*\d{2,}\w*\//i, /\.akamaized\.net\/i\/u\/[a-z]*\d{2,}\w*\//gi, ".akamaized.net/i/u/"],
        [/last(fm)?\.[a-z]{2,3}/, /\.net\/i\/u\/[a-zA-Z]*\d{2,}\w*\//i, /\.net\/i\/u\/[a-z]*\d{2,}\w*\//gi, ".net/i/u/"], // fix 2019-10-26
        [/magnatune\./, /cover_\d{2,3}\./i, /cover_\d{2,3}\./gi, "cover."],
        [/musicbrainz\.org/, /_thumb\d{3}\./i, /_thumb\d{3}\./gi, "."],
        [/musicbrainz\.org/, /-\d{3}\.jpg/i, /-\d{3}\.jpg/gi, ".jpg"],
        [/musicbrainz\.org/, /-\d{3}\.png/i, /-\d{3}\.png/gi, ".png"],
        [/musicdiner\./, /\/\d{2,3}x\d{2,3}bb/i, /\/\d{2,3}x\d{2,3}bb/gi, "/999999x999999bb-100"],
        [/play\.google\.com/, /googleusercontent\.com.*\=w\d{3}/i, /\=w\d{3}$/gi, "=w1200"],
        [/qobuz\.com/, /static\.qobuz\.com\/images\/covers\//i, /_\d{2,3}\.jpg/gi, "_max.jpg"],
        [/trackitdown\.net/, /\.cloudfront.net\/graphics\//i, /__\w+\.png/gi, "_original.jpg"],
        [/soundcloud\./, /t\d\d0x\d\d0\./i, /t\d\d0x\d\d0\./gi, "original."],
        [/open\.spotify\.com/, /i\.scdn\.co\/image\/ab67616d0000/i, /ab67616d00001e02/gi, "ab67616d0000b273"]];
    /* https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/ */
    let aEv = function (e,ev,f,c) {
        c=(c)?c:false;
        if(e.addEventListener) {
            e.addEventListener(ev,f,c);
        } else if(e.attachEvent) {
            e.attachEvent("on"+ev,f);
        } else {
            e["on"+ev]=f;
        }
    };
    let w = null, n = 0, m = 20, d = document, i=0;

    // General preburner
    let pictures = document.querySelectorAll("picture");
    const PURL = /^[^\s,]+/im;
    pictures.forEach(
        function(picture, idx) {
            let img = picture.querySelector("img");
            let source = picture.querySelector("source");
            if (img) {
                // img.removeAttribute("loading");
                let currentSrc = img.currentSrc;
                if (source && source.srcset) {
                    if (!currentSrc || currentSrc.endsWith("1x1.gif") || currentSrc.endsWith("MissingArtworkMusic.svg")) {
                        let url = source.srcset.match(PURL);
                        if (url) {
                            currentSrc = url[0];
                        }
                    }
                }
                picture.replaceWith(img);
                if (currentSrc && !(currentSrc.endsWith("1x1.gif") || currentSrc.endsWith("MissingArtworkMusic.svg"))) {
                    img.src = currentSrc;
                    img.removeAttribute("loading"); // I don't really understand, but removing loading-attribut at this point seems to work better than doing it earlier?
                }
            }
        }
    );

    // soundcloud pre-burner
    if (d.location.hostname.search(/soundcloud\./) > -1) {
        let spans = document.querySelectorAll("span[style*=background-image]");
        for (i = 0; i < spans.length; i++) {
            if (spans[i].style.backgroundImage) {
                let imgsrc = spans[i].style.backgroundImage.match(/url[\(\"\u0027]+([^\"\u0027\)]*)[\)\"\u0027]+/)[1];
                if ((spans[i].getElementsByTagName("img").length === 0) && (imgsrc.match(/t[\d]{3}x[\d]{3}\./) !== null)) {
                    spans[i].innerHTML = "<img src=\u0027" + imgsrc + "\u0027 alt=\u0027\u0027 style=\u0027width:200px;height:200px;border:none\u0027 />";
                }
            }
        }
    }
    // itunes/apple music pre-burner
    if (d.location.hostname.search(/\.apple\./) > -1) {
        let overlays = document.querySelectorAll(".artwork-overlay, .lockup__controls, .lockup__contextual-menu-trigger");
        for (i = 0; i < overlays.length; i++) {
            overlays[i].parentNode.removeChild(overlays[i]);
        }
    }
    // deezer pre-burner
    if (d.location.hostname.search(/deezer\.com/) > -1) {
        let pics = document.querySelectorAll("figure.thumbnail>div.picture");
        for (i = 0; i < pics.length; i++) {
            pics[i].classList.remove('picture');
        }
    }
    // last.fm pre-burner
    if (d.location.hostname.search(/last(fm)?\.[a-z]{2,3}/) > -1) {
        let elms = document.querySelectorAll(('.album-overview-cover-art-actions'));
        for (i=0; i < elms.length; i++) {
            elms[i].parentNode.removeChild(elms[i]);
        }
        let imgs = document.querySelectorAll(('a.cover-art img, a.image-list-item img'));
        for (i=0; i < imgs.length; i++) {
            imgs[i].style.maxWidth="370px";
            imgs[i].style.maxHeight="370px";
            imgs[i].parentNode.parentNode.replaceChild(imgs[i], imgs[i].parentNode); // (newchild, oldchild)
        }
    }

    log('Activated while on ' + d.location.hostname);
    o:
        for (let v = 0; v < a.length; v++) {
            if (d.location.hostname.search(a[v][0]) > -1) {
                log('Running on ' + d.location.hostname);
                w = a[v];
                let l = d.getElementsByTagName("img");
                if (l) {
                    log('Found ' + l.length + ' image tags');
                    for (i = 0; i < l.length; i++) {
                        // log(' - ' + l[i].currentSrc + ' . Includes ' + w[1] + '?: ' + ((l[i].currentSrc).search(w[1]) > -1) );
                        if ((l[i].currentSrc).search(w[1]) > -1) {
                            l[i].style.border = "1px #FB0 solid";
                            if (l[i].naturalWidth) {
                                // l[i].title = "just testing"; // adding dimemsions later on onload image?
                                // l[i].parentNode.title = "just testing parent"; // adding dimemsions later on onload image?
                                l[i].onmouseover = function () { // onmouseover via w3 metode. Eller på niveauet over og tage dimension på første img child???
                                    this.setAttribute("title", String(this.naturalWidth) + "x" + this.naturalHeight);
                                    this.setAttribute("data-title", String(this.naturalWidth) + "x" + this.naturalHeight);
                                    this.setAttribute("data-tooltip", String(this.naturalWidth) + "x" + this.naturalHeight);
                                };
                            }
                            aEv(l[i], "load", function () {
                                if (this.style) {
                                    this.style.borderColor = "#F00";
                                    if (this.naturalWidth && this.naturalWidth > 999) {
                                        this.style.borderWidth = "2px";
                                    }
                                }
                                // Sæt titles HER istedet !!!
                                // this.title = "Done loading: " + String(this.naturalWidth) + "x" + this.naturalHeight;
                                // this.parentNode.title = "Done loading: " + String(this.naturalWidth) + "x" + this.naturalHeight;
                            });
                            aEv(l[i], "click", function () {
                                if (this.currentSrc) {
                                    window.location = this.currentSrc;
                                }
                            });
                            // Lets take the change and do a general substitution of .webp for .jpg on all sites supported!
                            l[i].src = l[i].currentSrc.replace(w[2], w[3]).replace(/\.webp$/i, ".jpg");
                            if (l[i].srcset) {
                                l[i].removeAttribute('srcset')
                            }
                            n++;
                            if (n === m) {
                                if (confirm(String(n) + " images requested. Continue?")) {
                                    m = m + 20;
                                } else {
                                    break o;
                                }
                            }
                        }
                    }
                }
            }
        }
    if (w === null) {
        log('No hits found...');
    }
    return void(0);
}

function createRichElement(tagName, attributes, ...content) {
    let element = document.createElement(tagName);
    if (attributes) {
        for (const [attr, value] of Object.entries(attributes)) {
            element.setAttribute(attr, value);
        }
    }
    if (content && content.length) {
        element.append(...content);
    }
    return element;
}
function showGrabrLog() {
    document.getElementById('grabrlog').style.display = 'block';
}
if (typeof GM_info === 'object' || (typeof GM === 'object' && typeof GM.info === 'object')) {
    // Running as a userscript - setting up menu items...
    if (!document.getElementById('grabrlog')) {
        let gmwe = createRichElement("div", {id: "grabrlog"}, createRichElement("b", {},"Stig's Art Grabr changelog"), document.createElement("ul"));
        gmwe.style.position = "fixed";
        gmwe.style.left = "0";
        gmwe.style.right = "0";
        gmwe.style.top = "10em";
        gmwe.style.zIndex = "3000009";
        gmwe.style.marginLeft = "auto";
        gmwe.style.marginRight = "auto";
        gmwe.style.minHeight = "8em";
        gmwe.style.width = "50%";
        gmwe.style.backgroundColor = "#eee";
        gmwe.style.color = "#111";
        gmwe.style.borderRadius = "5px";
        gmwe.style.display = "none";
        gmwe.style.padding = "1em";
        document.body.insertAdjacentElement("beforeend", gmwe);
        document.getElementById('grabrlog').addEventListener('click',function(){this.style.display = 'none';return false;}, false);
        let list = document.querySelector('div#grabrlog ul');
        let lcontent = '';
        for (let i=0; i<Math.min(8,changelog.length); i++) {
            lcontent += '<li><i>'+changelog[i].version+'</i> - '+changelog[i].description+'</li>';
        }
        list.insertAdjacentHTML('beforeend', lcontent);
    }
    GMC.registerMenuCommand("Search big size cover art", runGrabr, "a");
    GMC.registerMenuCommand("Changelog", showGrabrLog, "l");
} else {
    // Started from bookmarklet!
    runGrabr();
}

function FIX_SPOTIFY_IMAGE(){
    console.log("RUNNING FIX_SPOTIFY_IMAGE...");
    function convertSpecificImageUrl4(url) {
        console.log("CONVERT: " + url);
    const regex = /https:\/\/is(\d+)-ssl\.mzstatic\.com\/image\/thumb\/Music(\d+)\/v4\/(.+\/.+)\.jpg\/999999x999999bb-100\.jpg/;
    let match = url.match(regex);
        console.log("match?:" + match);

    if (match) {
        console.log("MATCH");
        console.log(match);
        let subdomainIndex = match[1];
        console.log("subdomainIndex: " + subdomainIndex);
        let musicFolder = match[2];
        console.log("musicFolder: " + subdomainIndex);
        let artworkPath = match[3];
        console.log("artworkPath: " + subdomainIndex);
        let newUrl = `https://a${subdomainIndex}.mzstatic.com/us/r1000/063/Music${musicFolder}/v4/${artworkPath}.jpg`;
    }

    return url;
}

function convertSpecificImageUrl(url) {
    // Pattern matching for specific type of URL
    const regex = /https:\/\/is(\d+)-ssl\.mzstatic\.com\/image\/thumb\/Music(\d+)\/v4\/(.+\/.+)\.jpg\/999999x999999bb-100\.jpg/;
    let match = url.match(regex);

    if (match) {
        let subdomainIndex = match[1];
        let musicFolder = match[2];
        let artworkPath = match[3];

        // Construct new URL
        let newUrl = `https://a${subdomainIndex}.mzstatic.com/us/r1000/063/Music${musicFolder}/v4/${artworkPath}.jpg`;
        return newUrl;
    }

    return url; // Return original URL if no match
}

function findAndReplaceImages() {
    console.log("FINDING...");
    const images = document.querySelectorAll("img");
    console.log("imaged" + images);

    images.forEach(img => {
        let currentSrc = img.src;
        console.log("currentSrc: " + currentSrc);

        // Skip if the image has already been processed
        if (img.dataset.artProcessed) return;

        let newSrc = convertSpecificImageUrl(currentSrc);
        console.log("newSrc: " + newSrc);

        if (newSrc !== currentSrc) {
            img.src = newSrc;
            img.dataset.artProcessed = "true"; // Mark the image as processed
            img.style.border = "2px solid green !important"; // Optional: Visual cue that image has been replaced
        }
    });
}

// Call this function to perform the replacement
findAndReplaceImages();

}

// Add the automatic execution for Apple Music at the end of your script
if (window.location.hostname.includes("music.apple.com")) {
    window.addEventListener('load', function() {
        runGrabr();
        FIX_SPOTIFY_IMAGE();
    });
}
StigNygaard commented 7 months ago

Hi @daoxi and @tyhallcsu

I must admit that I have not only been busy with other projects, but motivation to work with Art Grabr had also taken a big dive. But thanks for reporting, code tips and simply just insisting 😊 I have just released the first new version of Art Grabr in 2 2/3 year, which I believe fixes this issue.

I will try to look at Amazon and other sites some other day. Doesn't promise anything specific, but hopefully it wont be 2 2/3 years again 😉

HeartbeatingForCenturies commented 7 months ago

hey thanks for the update, it seems to have broken new itunes albums tho e.g https://music.apple.com/us/album/the-fool/1624740203

daoxi commented 7 months ago

hey thanks for the update, it seems to have broken new itunes albums tho e.g https://music.apple.com/us/album/the-fool/1624740203

I haven't tested the new version yet since it's been a couple of years since I last used Stig's Art Grabr, but in the meantime as an alternative you can try a simple bookmarklet script I wrote a couple of years ago, seems to be able to grab the original album art just fine.

thanks StigNygaard for continuing maintaining Stig's Art Grabr's repo.

StigNygaard commented 7 months ago

hey thanks for the update, it seems to have broken new itunes albums tho e.g https://music.apple.com/us/album/the-fool/1624740203

Argh, I knew I should have tested it a bit more 😊 Looks like it is because it has a PNG image as original cover. I currently only expect/handle JPG and WEBP. If it is only that, I should be able to fix it very quickly...

StigNygaard commented 7 months ago

@HeartbeatingForCenturies & @daoxi, it should be fixed now in the just released update. Hopefully 😊