NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Currency Calculator // @namespace https://openuserjs.org/ // @version 2.6.3 // @description Currency calculator with API integration // @author Didi // @match https://cbr.ru/* // @grant none // @run-at document-end // @require https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js // @license MIT // @updateURL https://openuserjs.org/meta/Didi/currency_calculator.meta.js // ==/UserScript== (function() { if (typeof document.addEventListener !== 'function') { console.log('Ваш браузер устарел. Пожалуйста, обновите его.'); return; } document.addEventListener('DOMContentLoaded', function() { // Гарантируем загрузку DOM 'use strict'; // Проверяем, что скрипт запущен на нужном сайте if (window.location.hostname !== 'cbr.ru') { return; + ' + // Проверка наличия API ключа в localStorage var apiKey = 'ВАШ_API_КЛЮЧ_ЗДЕСЬ'; if (!apiKey) { // Если ключа нет, создаем форму для ввода var apiKeyForm = document.createElement('div'); apiKeyForm.innerHTML = ' + <h1>Введите ваш API ключ от Open Exchange Rates:</h1> <input type="text" id="apiKeyInput" placeholder="Введите API ключ"> <button id="apiKeySubmit">Сохранить</button> '; document.body.appendChild(apiKeyForm); document.getElementById('apiKeySubmit').addEventListener('click', () => { apiKey = document.getElementById('apiKeyInput').value; localStorage.setItem('openExchangeRatesApiKey', apiKey); location.reload(); // Перезагружаем страницу после сохранения ключа + '); return; // Прерываем выполнение, пока ключ не введен + ' + // Создаем основной контейнер var calculatorContainer = document.createElement('div'); calculatorContainer.style.position = 'fixed'; calculatorContainer.style.top = '10px'; calculatorContainer.style.right = '10px'; calculatorContainer.style.backgroundColor = 'white'; calculatorContainer.style.border = '1px solid black'; calculatorContainer.style.padding = '8px'; calculatorContainer.style.zIndex = '10000'; calculatorContainer.style.boxShadow = '0 0 10px rgba(0, 0, 0, 0.2)'; calculatorContainer.style.width = '300px'; calculatorContainer.style.maxHeight = '75vh'; calculatorContainer.style.overflowY = 'auto'; calculatorContainer.style.overflowX = 'hidden'; calculatorContainer.style.fontSize = '0.85em'; calculatorContainer.style.lineHeight = '1.2'; // API и настройки кэширования var apiUrl = 'https://openexchangerates.org/api/latest.json?app_id=' + apiKey + '&symbols=RUB,EUR'; var storageKey = 'cachedExchangeRate'; var storageDateKey = 'cachedExchangeRateDate'; var storageRequestCountKey = 'apiRequestCount'; var maxRequestsPerDay = 90; var refreshIntervalMinutes = 10; var currentMode = 'RUB'; var currencyType = 'RUB'; // Элемент для отображения курса евро var exchangeRateDisplay = document.createElement('p'); exchangeRateDisplay.textContent = 'Загрузка курса евро...'; exchangeRateDisplay.style.fontWeight = 'bold'; exchangeRateDisplay.style.margin = '5px 0'; exchangeRateDisplay.style.fontSize = '0.95em'; calculatorContainer.appendChild(exchangeRateDisplay); // Поле для ввода курса валюты var exchangeRateField = document.createElement('input'); exchangeRateField.type = 'number'; exchangeRateField.placeholder = 'Введите курс вручную'; exchangeRateField.step = '0.0001'; exchangeRateField.style.width = '280px'; exchangeRateField.style.margin = '5px 0'; exchangeRateField.style.padding = '3px'; exchangeRateField.style.fontSize = '0.9em'; calculatorContainer.appendChild(exchangeRateField); // Поле для ввода суммы var amountField = document.createElement('input'); amountField.type = 'number'; amountField.placeholder = 'Введите сумму'; amountField.style.width = '280px'; amountField.style.margin = '5px 0'; amountField.style.padding = '3px'; amountField.style.fontSize = '0.9em'; calculatorContainer.appendChild(amountField); // Кнопки выбора режима var modeContainer = document.createElement('div'); modeContainer.style.margin = '5px 0'; modeContainer.style.display = 'flex'; modeContainer.style.justifyContent = 'space-between'; modeContainer.style.gap = '5px'; var rubModeButton = document.createElement('button'); rubModeButton.textContent = 'Хотят рубли'; rubModeButton.style.backgroundColor = 'lightgreen'; rubModeButton.style.flex = '1'; rubModeButton.style.padding = '4px'; rubModeButton.style.fontSize = '0.9em'; var eurModeButton = document.createElement('button'); eurModeButton.textContent = 'Хотят евро'; eurModeButton.style.flex = '1'; eurModeButton.style.padding = '4px'; eurModeButton.style.fontSize = '0.9em'; rubModeButton.addEventListener('click', function() { currentMode = 'RUB'; rubModeButton.style.backgroundColor = 'green'; eurModeButton.style.backgroundColor = ''; + '); eurModeButton.addEventListener('click', function() { currentMode = 'EUR'; eurModeButton.style.backgroundColor = 'green'; rubModeButton.style.backgroundColor = ''; + '); modeContainer.appendChild(rubModeButton); modeContainer.appendChild(eurModeButton); calculatorContainer.appendChild(modeContainer); // Кнопки выбора типа валюты var currencyTypeContainer = document.createElement('div'); currencyTypeContainer.style.margin = '5px 0'; currencyTypeContainer.style.display = 'flex'; currencyTypeContainer.style.justifyContent = 'space-between'; currencyTypeContainer.style.gap = '5px'; var rubleButton = document.createElement('button'); rubleButton.textContent = 'Рубли'; rubleButton.style.backgroundColor = 'lightgray'; rubleButton.style.flex = '1'; rubleButton.style.padding = '4px'; rubleButton.style.fontSize = '0.9em'; var euroButton = document.createElement('button'); euroButton.textContent = 'Евро'; euroButton.style.flex = '1'; euroButton.style.padding = '4px'; euroButton.style.fontSize = '0.9em'; rubleButton.addEventListener('click', function() { currencyType = 'RUB'; rubleButton.style.backgroundColor = 'green'; euroButton.style.backgroundColor = ''; + '); euroButton.addEventListener('click', function() { currencyType = 'EUR'; euroButton.style.backgroundColor = 'green'; rubleButton.style.backgroundColor = ''; + '); currencyTypeContainer.appendChild(rubleButton); currencyTypeContainer.appendChild(euroButton); calculatorContainer.appendChild(currencyTypeContainer); // Контейнер для кнопок с процентами var percentageContainer = document.createElement('div'); percentageContainer.style.margin = '5px 0'; percentageContainer.style.display = 'flex'; percentageContainer.style.justifyContent = 'space-between'; percentageContainer.style.gap = '2px'; // Массив процентов var percentages = [3, 4, 5, 7, 10]; // Создаем кнопки для каждого процента percentages.forEach(function(percentage) { var button = document.createElement('button'); button.textContent = percentage + '%'; button.style.flex = '1'; button.style.padding = '4px'; button.style.fontSize = '0.9em'; button.style.minWidth = '45px'; button.addEventListener('click', function() { // Сбрасываем цвет всех кнопок Array.from(percentageContainer.children).forEach(function(btn) { btn.style.backgroundColor = ''; + '); // Устанавливаем зеленый цвет для нажатой кнопки this.style.backgroundColor = 'green'; var value = parseFloat(amountField.value); var exchangeRate = parseFloat(exchangeRateField.value) || parseFloat(exchangeRateDisplay.dataset.rate); if (!isNaN(value) && !isNaN(exchangeRate)) { var finalAmount, percentValue; var profitText; var resultText; if (currentMode === 'RUB') { if (currencyType === 'EUR') { percentValue = value * (percentage / 100); finalAmount = (value - percentValue) * exchangeRate; profitText = 'Ваш доход: ' + percentValue.toFixed(2) + ' евро'; + ' else { percentValue = value * (percentage / 100); finalAmount = value + percentValue / exchangeRate; profitText = 'Ваш доход: ' + percentValue.toFixed(2) + ' руб.'; + ' + + ' else if (currentMode === 'EUR') { if (currencyType === 'EUR') { percentValue = value * (percentage / 100); finalAmount = value + percentValue / exchangeRate; profitText = 'Ваш доход: ' + percentValue.toFixed(2) + ' евро'; + ' else { percentValue = value * (percentage / 100); finalAmount = (value - percentValue) / exchangeRate; profitText = 'Ваш доход: ' + percentValue.toFixed(2) + ' руб.'; + ' + + ' + if (currentMode === 'EUR' && currencyType === 'RUB') { resultText = 'Итог: ' + Math.round(finalAmount) + ' euro'; + ' else { resultText = 'Итог: ' + Math.round(finalAmount) + ' руб.'; + ' + displayResult(resultText, profitText); + ' + + '); percentageContainer.appendChild(button); + '); calculatorContainer.appendChild(percentageContainer); // Контейнер для результатов var resultContainer = document.createElement('div'); resultContainer.style.margin = '5px 0'; resultContainer.style.borderTop = '1px solid #ccc'; resultContainer.style.paddingTop = '5px'; calculatorContainer.appendChild(resultContainer); // Функция отображения результата function displayResult(resultText, profitText) { resultContainer.innerHTML = ''; var resultElement = document.createElement('p'); resultElement.textContent = resultText; resultElement.style.margin = '5px 0'; resultElement.style.fontSize = '0.95em'; resultContainer.appendChild(resultElement); var profitElement = document.createElement('p'); profitElement.textContent = profitText; profitElement.style.color = 'green'; profitElement.style.fontWeight = 'bold'; profitElement.style.margin = '5px 0'; profitElement.style.fontSize = '0.95em'; resultContainer.appendChild(profitElement); var buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.justifyContent = 'space-between'; buttonContainer.style.gap = '5px'; buttonContainer.style.margin = '5px 0'; var copyButton = document.createElement('button'); copyButton.textContent = 'Скопировать Итог'; copyButton.style.flex = '1'; copyButton.style.padding = '4px'; copyButton.style.fontSize = '0.9em'; copyButton.addEventListener('click', function() { var match = resultText.match(/(\d+)\s*(руб\.|euro)/); if (match) { var textToCopy = match[1] + ' ' + match[2]; copyToClipboard(textToCopy, copyButton); + ' + + '); var copyProfitButton = document.createElement('button'); copyProfitButton.textContent = 'Скопировать Доход'; copyProfitButton.style.flex = '1'; copyProfitButton.style.padding = '4px'; copyProfitButton.style.fontSize = '0.9em'; copyProfitButton.addEventListener('click', function() { var match = profitText.match(/(\d+\.?\d*)/); if (match) { var textToCopy = match[1].replace('.', ','); copyToClipboard(textToCopy, copyProfitButton); + ' + + '); buttonContainer.appendChild(copyButton); buttonContainer.appendChild(copyProfitButton); resultContainer.appendChild(buttonContainer); + ' + // Функция для отображения ошибок function displayError(errorText) { resultContainer.innerHTML = ''; var errorElement = document.createElement('p'); errorElement.style.color = 'red'; errorElement.style.margin = '5px 0'; errorElement.style.fontSize = '0.9em'; errorElement.textContent = errorText; resultContainer.appendChild(errorElement); + ' + // Функция копирования в буфер обмена function copyToClipboard(text, button) { var tempInput = document.createElement('input'); tempInput.value = text; document.body.appendChild(tempInput); tempInput.select(); document.execCommand('copy'); document.body.removeChild(tempInput); button.style.backgroundColor = 'green'; setTimeout(() => { button.style.backgroundColor = ''; + ', 1500); + ' + // Функция получения курса валют async function fetchAndCacheExchangeRate() { var cachedRate = localStorage.getItem(storageKey); var cachedDate = localStorage.getItem(storageDateKey); var requestCount = parseInt(localStorage.getItem(storageRequestCountKey) || '0', 10); var now = new Date(); var today = now.toISOString().split('T')[0]; if (cachedDate !== today) { localStorage.setItem(storageRequestCountKey, '0'); + ' + if (cachedRate && cachedDate === today) { exchangeRateDisplay.textContent = 'Курс евро: ' + cachedRate + ' руб.'; exchangeRateDisplay.dataset.rate = cachedRate; + ' else if (requestCount < maxRequestsPerDay) { try { var response = await fetch(apiUrl); var data = await response.json(); if (data && data.rates && data.rates.RUB && data.rates.EUR) { var euroToRubRate = (data.rates.RUB / data.rates.EUR).toFixed(4); exchangeRateDisplay.textContent = 'Курс евро: ' + euroToRubRate + ' руб.'; exchangeRateDisplay.dataset.rate = euroToRubRate; localStorage.setItem(storageKey, euroToRubRate); localStorage.setItem(storageDateKey, today); localStorage.setItem(storageRequestCountKey, (requestCount + 1).toString()); + ' else { displayError('Ошибка при получении курса евро.'); + ' + + ' catch (error) { console.error('Ошибка при запросе к Open Exchange Rates:', error); displayError('Ошибка при загрузке курса.'); + ' + + ' else { displayError('Лимит запросов на сегодня исчерпан.'); + ' + + ' + // Запускаем первичную загрузку курса fetchAndCacheExchangeRate(); // Обновляем курс каждые 10 минут setInterval(fetchAndCacheExchangeRate, refreshIntervalMinutes * 30 * 1000); // Добавляем калькулятор на страницу document.body.appendChild(calculatorContainer); + ')(); // Обход CORS function loadScriptWithCORS(url, onSuccess, onError) { GM.xmlHttpRequest({ method: 'GET', url: url, onload: function(response) { if (response.status === 200) { console.log('Скрипт загружен:', url); onSuccess(response.responseText); } else { console.error('Ошибка загрузки скрипта:', url, response.status); if (onError) onError(response.status); } }, onerror: function(error) { console.error('Ошибка сети:', error); if (onError) onError(error); } }); }