Vine Infinite Spinning Fix

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

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==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;
    };
})();