Vine Infinite Spinning Fix

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

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

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

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

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

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.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==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;
    };
})();