Vine Infinite Spinning Fix

Fixes the infinite spinning issue on Amazon Vine when trying to select a product variant

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

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

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Vine Infinite Spinning Fix
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Fixes the infinite spinning issue on Amazon Vine when trying to select a product variant
// @author       Prismaris
// @match        https://www.amazon.com.au/vine/vine-items*
// @match        https://www.amazon.com.be/vine/vine-items*
// @match        https://www.amazon.com.br/vine/vine-items*
// @match        https://www.amazon.ca/vine/vine-items*
// @match        https://www.amazon.cn/vine/vine-items*
// @match        https://www.amazon.eg/vine/vine-items*
// @match        https://www.amazon.fr/vine/vine-items*
// @match        https://www.amazon.de/vine/vine-items*
// @match        https://www.amazon.in/vine/vine-items*
// @match        https://www.amazon.it/vine/vine-items*
// @match        https://www.amazon.co.jp/vine/vine-items*
// @match        https://www.amazon.com.mx/vine/vine-items*
// @match        https://www.amazon.nl/vine/vine-items*
// @match        https://www.amazon.pl/vine/vine-items*
// @match        https://www.amazon.sa/vine/vine-items*
// @match        https://www.amazon.sg/vine/vine-items*
// @match        https://www.amazon.es/vine/vine-items*
// @match        https://www.amazon.se/vine/vine-items*
// @match        https://www.amazon.com.tr/vine/vine-items*
// @match        https://www.amazon.ae/vine/vine-items*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const origFetch = window.fetch;

    function showToast(message) {
        const toast = document.createElement('div');
        toast.textContent = message;
        toast.style.position = 'fixed';
        toast.style.bottom = '20px';
        toast.style.left = '50%';
        toast.style.transform = 'translateX(-50%)';
        toast.style.backgroundColor = '#333';
        toast.style.color = 'white';
        toast.style.padding = '10px 20px';
        toast.style.borderRadius = '5px';
        toast.style.zIndex = '1000';
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.remove();
        }, 3000);
    }

    window.fetch = async (...args) => {
        let response = await origFetch(...args);
        const url = args[0] || "";

        if (url.startsWith("api/recommendations")) {
            let responseData = await response.clone().json();
            let fixed = 0;
            let arrKeyNames = [];

            if (responseData.result && responseData.result.variations) {
                // Make the list of all keys/dimensions across all variants:
                for (const variation of responseData.result.variations) {
                    for (const key in variation.dimensions) {
                        if (!arrKeyNames.includes(key)) {
                            arrKeyNames.push(key);
                        }
                    }
                }

                responseData.result.variations = responseData.result.variations.map((variation) => {
                    if (Object.keys(variation.dimensions || {}).length === 0) {
                        variation.dimensions = {
                            asin_no: variation.asin,
                        };
                        fixed++;
                        return variation;
                    }

                    if (arrKeyNames.length > 0) {
                        for (const key of arrKeyNames) {
                            if (!variation.dimensions[key]) {
                                variation.dimensions[key] = "VH FIX";
                                fixed++;
                            }
                        }
                    }

                    for (const key in variation.dimensions) {
                        let newValue;
                        
                        //Replace all non-standard characters
                        newValue = variation.dimensions[key].replace(/[^a-zA-Z0-9\\(){}/.,"'¼½¾+&%# -]/g, "_");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        //& without a space after it will crash, add a space after it.
                        newValue = variation.dimensions[key].replace(/[&]([^\\s])/g, "& $1");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        //Escape the special characters
                        newValue = variation.dimensions[key].replace(/[/\\()[\]{}]/g, "\\$&");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        // Remove apostrophes / single quotes which can break jQuery selectors
                        newValue = variation.dimensions[key].replace(/'+/g, "");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        // Normalize comma-separated lists to ensure a space after commas
                        newValue = variation.dimensions[key].replace(/,\s*/g, ", ");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        // Any variation ending with a space will crash, ensure there is no space at the end.
                        newValue = variation.dimensions[key].replace(/\s+$/g, "");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        // The core of the issue is when a special character is at the end of a variation, the jQuery UI which amazon uses will attempt to evaluate it and fail since it attempts to utilize it as part of an html attribute.
                        // In order to resolve this, we make the string safe for an html attribute by escaping the special characters.
                        if (!variation.dimensions[key].match(/[a-z0-9)\\]]$/i)) {
                            variation.dimensions[key] = variation.dimensions[key] + ` VH${fixed}`;
                            fixed++;
                        }

                        // Any variation with a : or ) without a space after will crash, ensure : always has a space after.
                        newValue = variation.dimensions[key].replace(/([:)])([^\\s])/g, "$1 $2");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }

                        // Any variation with a ( with a space after will crash, ensure never has a space after.
                        newValue = variation.dimensions[key].replace(/([(])\\s/g, "$1");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }
                        // Any variation with a / with a space before it will crash, remove the space before.
                        newValue = variation.dimensions[key].replace(/(\\s[/])/g, "/");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }
                        // Any variation with a | by ;.
                        newValue = variation.dimensions[key].replace(/([|])/g, "-");
                        if (newValue !== variation.dimensions[key]) {
                            variation.dimensions[key] = newValue;
                            fixed++;
                        }
                    }

                    return variation;
                });
            }


            if (fixed > 0) {
                console.log(`Vine Infinite Spinning Fix: ${fixed} variation(s) fixed.`);
                showToast(`${fixed} variation(s) fixed.`);
            }

            return new Response(JSON.stringify(responseData));
        }

        return response;
    };
})();