Greasy Fork

Currency Converter

try to take over the world!

目前为 2017-07-29 提交的版本。查看 最新版本

// ==UserScript==
// @name         Currency Converter
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  try to take over the world!
// @icon         http://store.steampowered.com/favicon.ico
// @author       Bisumaruko
// @include      http*://yuplay.ru/*
// @include      http*://*.gamersgate.com/*
// @include      http*://www.greenmangaming.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.slim.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.6/sweetalert2.min.js
// @resource     SweetAlert2CSS https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/6.6.6/sweetalert2.min.css
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_getResourceText
// @run-at       document-start
// @connect      api.fixer.io
// ==/UserScript==

/*
    global GM_xmlhttpRequest, GM_setValue, GM_getValue, GM_addStyle, GM_getResourceText,
    $, swal,
    document, location, MutationObserver
*/

// inject css
GM_addStyle(GM_getResourceText('SweetAlert2CSS'));

// setup swal
swal.setDefaults({
    timer: 3000,
    useRejections: false,
});

// load config
const config = JSON.parse(GM_getValue('Bisko_CC', '{}'));
const interval = 3 * 60 * 60 * 1000; // update exchange rate every 3 hours

// constructing functions
const has = Object.prototype.hasOwnProperty;
const preferredCurrency = () => {
    const preferred = config.preferredCurrency;

    if (has.call(config.exchangeRate.rates, preferred)) return preferred;
    return 'CNY';
};
const updateCurrency = (currency = null) => {
    const targetCurrency = currency || preferredCurrency();
    const symbols = {
        AUD: 'AU$',
        CAD: 'CA$',
        CNY: 'CN¥',
        EUR: '€',
        GBP: '£',
        HKD: 'HK$',
        JPY: 'JP¥',
        KRW: '₩',
        MYR: 'RM',
        NTD: 'NT$',
        NZD: 'NZ$',
        RUB: 'руб',
        USD: 'US$',
    };
    // converting price
    $('.currency_price').each((index, element) => {
        const $ele = $(element);
        const data = $ele.attr('data-price').split(' ');
        const originalCurrency = data[0];
        const originalPrice = parseFloat(data[1]);
        let convertedPrice = originalPrice;

        if (originalCurrency !== targetCurrency && targetCurrency !== 'ORI') {
            const toBase = originalPrice / config.exchangeRate.rates[originalCurrency];
            const toTarget = toBase * config.exchangeRate.rates[targetCurrency];

            convertedPrice = toTarget.toFixed(2);
        }

        $ele.text(convertedPrice);
    });
    // replacing currency symbol
    const originalCurrency = $('.currency_name').attr('data-currency');
    const symbol = targetCurrency === 'ORI' ? symbols[originalCurrency] : symbols[targetCurrency];

    $('.currency_name').text(symbol);
};
const constructMenu = () => {
    const $li = $('<li class="Bisko_CC_Menu"><a>Currencies</a></li>');
    const $ul = $('<ul></ul>').appendTo($li);
    const currencies = {
        ORI: '恢復',
        AUD: '澳幣',
        CAD: '加幣',
        CNY: '人民幣',
        EUR: '歐元',
        GBP: '英鎊',
        HKD: '港幣',
        JPY: '日圓',
        KRW: '韓圓',
        MYR: '令吉',
        NTD: '台幣',
        NZD: '紐幣',
        RUB: '盧布',
        USD: '美元',
    };
    const preferred = preferredCurrency();

    GM_addStyle(`
        .Bisko_CC_Menu ul {
            display: none;
            position: absolute;
            padding: 0;
            background-color: #272727;
            z-index: 9999;
        }
        .Bisko_CC_Menu:hover ul {
            display: block;
        }
        .Bisko_CC_Menu li {
            padding: 2px 10px;
            list-style-type: none;
            cursor: pointer;
        }
        .Bisko_CC_Menu li:hover, .preferred {
            background-color: SandyBrown;
        }
    `);

    Object.keys(currencies).forEach((currency) => {
        const itemName = `${currency} ${currencies[currency]}`;

        $ul.append(
            $(`<li class="${currency}">${itemName}</li>`)
            .addClass(() => (preferred === currency ? 'preferred' : ''))
            .click(() => {
                config.preferredCurrency = currency;

                GM_setValue('Bisko_CC', JSON.stringify(config));
                updateCurrency(currency);

                $('.Bisko_CC_Menu .preferred').removeClass('preferred');
                $(`.Bisko_CC_Menu .${currency}`).addClass('preferred');
            }),
        );
    });

    return $li;
};
const handler = () => {
    switch (location.host) {
        case 'yuplay.ru':
            GM_addStyle(`
                .games-pricedown span.currency_price {
                    font-size: 18px;
                }
                .good-title span.currency_price {
                    margin-right: 3px;
                    font-size: 22px;
                }
            `);

            $('.header-right').append(constructMenu());
            $('.price')
                .each((index, element) => {
                    $(element).contents().each((i, node) => {
                        const $node = $(node);

                        if (node.tagName === 'S') { // retail price node
                            $node
                                .addClass('currency_price')
                                .attr('data-price', `RUB ${$node.text().trim()}`);
                        } else if (node.nodeType === 3) { // sales price node
                            const price = node.textContent.trim();

                            if ($.isNumeric(price)) $node.replaceWith(`<span class="currency_price" data-price="RUB ${price}">${price}</span>`);
                        } else if (node.tagName === 'SPAN') { // currency node
                            $node
                                .addClass('currency_name')
                                .attr('data-currency', 'RUB');
                        }
                    });
                })
                .prev('.sale').find('s')
                .each((i, node) => {
                    const $node = $(node);

                    $node
                        .addClass('currency_price')
                        .attr('data-price', `RUB ${$node.text().trim()}`);
                });
            break;
//        case 'www.gamersgate.com':
        case 'ru.gamersgate.com':
        case 'cn.gamersgate.com': {
            let originalCurrency = '';

            if (location.host.startsWith('ru')) originalCurrency = 'RUB';
            if (location.host.startsWith('cn')) originalCurrency = 'CNY';

            GM_addStyle(`
                .Bisko_CC_Menu {
                    width: 49px;
                    text-align: center;
                }
                .Bisko_CC_Menu svg {
                    width: 36px;
                    height: 36px;
                    background-color: #093745;
                    border: 1px solid #2c7c92;
                }
                .Bisko_CC_Menu, .Bisko_CC_Menu li {
                    background-image: none !important;
                    color: white;
                }
                .Bisko_CC_Menu li {
                    height: initial !important;
                    float: none !important;
                    padding: 5px 10px !important;
                }
                .Bisko_CC_Menu li:hover, .preferred {
                    background-color: SandyBrown !important;
                }
            `);

            $('.btn_menuseparator').replaceWith(constructMenu());
            $('.Bisko_CC_Menu a').replaceWith(`
                <svg viewBox="0 0 24 24">
                    <path fill="#a9ebea" d="M11.8,10.9C9.53,10.31 8.8,9.7 8.8,8.75C8.8,7.66 9.81,6.9 11.5,6.9C13.28,6.9 13.94,7.75 14,9H16.21C16.14,7.28 15.09,5.7 13,5.19V3H10V5.16C8.06,5.58 6.5,6.84 6.5,8.77C6.5,11.08 8.41,12.23 11.2,12.9C13.7,13.5 14.2,14.38 14.2,15.31C14.2,16 13.71,17.1 11.5,17.1C9.44,17.1 8.63,16.18 8.5,15H6.32C6.44,17.19 8.08,18.42 10,18.83V21H13V18.85C14.95,18.5 16.5,17.35 16.5,15.3C16.5,12.46 14.07,11.5 11.8,10.9Z" />
                </svg>
            `);
            const prices = $('.price_price, .prtag, li > .f_right:nth-child(2)');

            prices.each((index, element) => {
                $(element)
                    .css('padding-right', '5px')
                    .find('span').each((i, node) => {
                        const $node = $(node);
                        const price = parseFloat($node.text().replace(/[^.0-9]/g, ''));

                        $node
                            .addClass('currency_price')
                            .attr('data-price', `${originalCurrency} ${price}`)
                            .after(`<span class="currency_name" data-currency="${originalCurrency}"></span>`);
                    });
            });

            prices.prev().prev()
                .find('.bold.white')
                .each((index, element) => {
                    const $ele = $(element);
                    const price = parseFloat($ele.text().replace(/[^.0-9]/g, ''));

                    $ele
                        .addClass('currency_price')
                        .attr('data-price', `${originalCurrency} ${price}`);
                });

            prices.closest('.descr_cont').next().find('.grid-old-price').each((index, element) => {
                const $ele = $(element);
                const price = parseFloat($ele.text().replace(/[^.0-9]/g, ''));

                $ele.html(`
                    <span class="currency_price" data-price="${originalCurrency} ${price}"></span>
                    <span class="currency_name" data-currency="${originalCurrency}"></span>
                `);
            });
            break;
        }
        case 'www.greenmangaming.com': {
            GM_addStyle(`
                .Bisko_CC_Menu > a {
                    margin: 0 !important;
                    padding: 6px 15px !important;
                    font-size: 14px;
                }
                .Bisko_CC_Menu > a:hover, .Bisko_CC_Menu li:hover, .preferred {
                    background-color: #494a4f !important;
                }
            `);

            $('.megamenu').append(constructMenu());

            let homepage = false;
            let originalCurrency = $('.currency-code').eq(0).text();
            const GMGHandler = (index, element) => {
                const $ele = $(element);
                let price = parseFloat($ele.text().replace(/[^.0-9]/g, ''));

                if (homepage && ['RUB'].includes(originalCurrency)) price /= 100;

                $ele.html(`
                    <span class="currency_name" data-currency="${originalCurrency}"></span>
                    <span class="currency_price" data-price="${originalCurrency} ${price}"></span>
                `);
            };
            // home page
            if (originalCurrency.length === 0) {
                const observer = new MutationObserver((mutations) => {
                    mutations.forEach((mutation) => {
                        mutation.addedNodes.forEach((addedNode) => {
                            if (addedNode.src && addedNode.src.includes('bam.nr-data.net')) {
                                const src = decodeURI(addedNode.src);
                                originalCurrency = src.split('currency_code":"').pop().slice(0, 3) || 'USD';
                                homepage = true;

                                $('.prices > span').each(GMGHandler);
                                updateCurrency();
                                observer.disconnect();
                            }
                        });
                    });
                });

                observer.observe(document.head, {
                    childList: true,
                });
            } else $('price > span').each(GMGHandler); // product page
            break;
        }
        default:
    }

    updateCurrency();
};
const getExchangeRate = () => {
    GM_xmlhttpRequest({
        method: 'GET',
        url: 'http://api.fixer.io/latest',
        onload: (res) => {
            if (res.status === 200) {
                try {
                    const exchangeRate = JSON.parse(res.response);

                    config.exchangeRate = exchangeRate;
                    config.lastUpdate = Date.now();
                    // add EUR, NTD
                    config.exchangeRate.rates.EUR = 1;
                    config.exchangeRate.rates.NTD = config.exchangeRate.rates.HKD * 3.9;

                    GM_setValue('Bisko_CC', JSON.stringify(config));
                    handler();
                } catch (e) {
                    swal(
                        'Parsing Failed',
                        'An error occured when parsing exchange rate data, please reload to try again',
                        'error',
                    );
                }
            } else {
                swal(
                    'Loading Failed',
                    'Unable to fetch exchange rate data, please reload to try again',
                    'error',
                );
            }
        },
    });
};

$(() => {
    if (Object.keys(config).length === 0) getExchangeRate(); // first installed
    else if (Date.now() - interval > config.lastUpdate) getExchangeRate(); // update exchange rate
    else handler();
});