├── icons ├── LLTStoreTrueprice16.png ├── LLTStoreTrueprice32.png ├── LLTStoreTrueprice48.png ├── LLTStoreTrueprice128.png ├── clear.svg └── LLTStoreTrueprice.svg ├── popup ├── options-dark.css ├── options-light.css ├── options.js ├── options.css └── options.html ├── manifest.json ├── README.md ├── LICENSE └── background.js /icons/LLTStoreTrueprice16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfly117/LTTStoreRealPrice/HEAD/icons/LLTStoreTrueprice16.png -------------------------------------------------------------------------------- /icons/LLTStoreTrueprice32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfly117/LTTStoreRealPrice/HEAD/icons/LLTStoreTrueprice32.png -------------------------------------------------------------------------------- /icons/LLTStoreTrueprice48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfly117/LTTStoreRealPrice/HEAD/icons/LLTStoreTrueprice48.png -------------------------------------------------------------------------------- /icons/LLTStoreTrueprice128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfly117/LTTStoreRealPrice/HEAD/icons/LLTStoreTrueprice128.png -------------------------------------------------------------------------------- /popup/options-dark.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --background-color: #191919; 3 | --font-color: #fff; 4 | --border-color: #fff; 5 | --field-background-color: #000; 6 | --field-border-color: #fff; 7 | --color-gradient: linear-gradient(to right, #1a2a6c, #b21f1f, #ac7f1f); 8 | } -------------------------------------------------------------------------------- /popup/options-light.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --background-color: #eee; 3 | --font-color: #000; 4 | --border-color: #121212; 5 | --field-background-color: #fff; 6 | --field-border-color: #e3e3e3; 7 | --color-gradient: linear-gradient(92.28deg, #e31886 2.18%, #fb7800 90.32%); 8 | } 9 | 10 | input[type="search"]::-webkit-search-cancel-button { 11 | filter: invert(); 12 | } -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "LTTStore.com Real Price ", 4 | "description": "This Extention take the price of items on LTTStore.com and add tax and shipping to the prices.", 5 | "version": "0.2.1", 6 | "permissions": ["storage", "scripting", "tabs"], 7 | "host_permissions": [ 8 | "*://www.lttstore.com/*" 9 | ], 10 | "icons": { 11 | "16": "/icons/LLTStoreTrueprice16.png", 12 | "48": "/icons/LLTStoreTrueprice48.png", 13 | "128": "/icons/LLTStoreTrueprice128.png" 14 | }, 15 | "action": { 16 | "default_popup": "popup/options.html" 17 | }, 18 | "background": { 19 | "service_worker": "background.js" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LTTStoreRealPrice 2 | 3 | ![image](https://github.com/user-attachments/assets/60e9986b-9acf-4dfa-833e-2acfad7fced0) 4 | 5 | 6 | This is a Chrome and Edge (Version 115.0.1901.183 tested) extension. I have not tried it with Edge or Firefox. 7 | 8 | #Installation - Chrome 9 | 10 | 1. Download the zip file and unpack it. 11 | 12 | 2. type chrome://extensions/ in the URL bar 13 | 14 | 3. turn on the dev settings (top right) 15 | 16 | 4. Then click load unpacked (top left) 17 | 18 | 5. navigate to the unpacked folder (parent folder) this should be "LTTStoreRealPrice" Select folder 19 | 20 | 6. Pin the extension, go to the LTTstore page, click the extension icon, and fill in the settings. 21 | 22 | ![xMFbnfP](https://github.com/highfly117/LTTStoreRealPrice/assets/32913685/f8190cd6-c5fe-4138-b12d-9fefdb105ac3) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Adam Wadsworth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /popup/options.js: -------------------------------------------------------------------------------- 1 | document.getElementById('saveButton').onclick = function () { 2 | let taxRate = document.getElementById('taxRate').value; 3 | let shippingCost = document.getElementById('shipping-cost').value; 4 | let currency = document.getElementById('currency').value; 5 | let shipping = document.getElementById('shipping').value; 6 | 7 | chrome.storage.sync.set({ 8 | taxRate: taxRate, 9 | shippingCost: shippingCost, 10 | currency: currency, 11 | shipping: shipping 12 | }, function () { 13 | // Display a success message 14 | let status = document.getElementById('status'); 15 | status.textContent = 'Options saved.'; 16 | 17 | // Clear the message after a few seconds 18 | setTimeout(function () { 19 | status.textContent = ''; 20 | }, 3000); 21 | 22 | chrome.storage.sync.get('tabId', function (data) { 23 | let tabId = data.tabId; 24 | 25 | // Check if we have a valid tabId 26 | if (tabId) { 27 | // Reload the tab 28 | chrome.tabs.reload(tabId); 29 | } 30 | }); 31 | }); 32 | }; 33 | 34 | window.onload = function () { 35 | chrome.storage.sync.get(['taxRate', 'shippingCost', 'currency', 'shipping'], function (data) { 36 | document.getElementById('shipping').value = data.shipping || ''; 37 | document.getElementById('taxRate').value = data.taxRate || ''; 38 | document.getElementById('shipping-cost').value = data.shippingCost || '19.99'; 39 | document.getElementById('currency').value = data.currency || 'USD'; 40 | }); 41 | }; -------------------------------------------------------------------------------- /icons/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 36 | 41 | 42 | -------------------------------------------------------------------------------- /popup/options.css: -------------------------------------------------------------------------------- 1 | html { 2 | width: 350px; 3 | padding: 20px; 4 | font-family: Poppins, sans-serif; 5 | font-weight: bold; 6 | color: var(--font-color); 7 | background-color: var(--background-color); 8 | cursor: default; 9 | } 10 | 11 | p, 12 | label { 13 | font-size: 20px; 14 | } 15 | 16 | button { 17 | background: var(--color-gradient); 18 | color: #fff; 19 | font-size: 1.5rem; 20 | width: 200px; 21 | height: 60px; 22 | border-radius: 10px; 23 | border-width: 0; 24 | border-color: var(--border-color); 25 | outline: none; 26 | transition: transform .2s; 27 | cursor: pointer; 28 | } 29 | 30 | button:hover { 31 | transform: scale(1.05); 32 | border-style: solid; 33 | border-width: 2px; 34 | } 35 | 36 | .input-box { 37 | display: flex; 38 | align-items: center; 39 | height: 45px; 40 | width: 150px; 41 | border-style: none; 42 | box-shadow: inset 0 0 0 2px var(--field-border-color); 43 | border-radius: 5px; 44 | border-color: var(--field-border-color); 45 | background-color: var(--field-background-color); 46 | outline: none; 47 | color: var(--font-color); 48 | padding-left: 15px; 49 | font-size: 20px; 50 | box-shadow: .3s ease-out; 51 | text-justify: inter-word; 52 | } 53 | 54 | .prefix { 55 | width: 20px; 56 | height: 31px; 57 | text-align: center; 58 | } 59 | 60 | input[type="number"], 61 | select, 62 | input { 63 | background: none; 64 | border: none; 65 | outline: none; 66 | color: var(--font-color); 67 | font-size: 20px; 68 | max-width: 150px; 69 | } 70 | 71 | datalist { 72 | width: 150px; 73 | } 74 | 75 | input[type="number"] { 76 | width: 117px; 77 | height: 40px; 78 | } 79 | 80 | .input-box:hover { 81 | box-shadow: inset 0 0 0 4px var(--field-border-color); 82 | } 83 | 84 | input[type="search"]::-webkit-search-cancel-button { 85 | -webkit-appearance: none; 86 | height: 1.25em; 87 | width: 1.25em; 88 | background: url(/icons/clear.svg); 89 | background-size: contain; 90 | } 91 | 92 | #header { 93 | display: flex; 94 | align-items: center; 95 | gap: 15px; 96 | padding-bottom: 30px; 97 | } 98 | 99 | #logo { 100 | width: 75px; 101 | } 102 | 103 | #header > h1 { 104 | color: #ff4d00; 105 | } 106 | 107 | #optionsContainer { 108 | display: flex; 109 | flex-direction: column; 110 | gap: 10px; 111 | border-radius: 5px; 112 | border-width: 2px; 113 | border-color: var(--border-color); 114 | padding-bottom: 30px; 115 | } 116 | 117 | #optionsContainer>div { 118 | display: flex; 119 | justify-content: space-between; 120 | align-items: center; 121 | } -------------------------------------------------------------------------------- /icons/LLTStoreTrueprice.svg: -------------------------------------------------------------------------------- 1 | 2 | 60 | -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | // background.js 2 | chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { 3 | if (tab.url.includes("https://www.lttstore.com/cart")) { 4 | return; 5 | } 6 | chrome.storage.sync.set({ tabId: tabId }); 7 | if (changeInfo.status === 'complete' && tab.url.startsWith('http')) { 8 | chrome.storage.sync.get(['taxRate', 'currency', 'rates', 'lastFetch', 'shippingCost', 'shipping'], function (data) { 9 | let taxRate = data.taxRate || 0; 10 | let currency = data.currency || 'USD'; 11 | let rates = data.rates || {}; 12 | let lastFetch = data.lastFetch; 13 | let shippingCost = Number(data.shippingCost); 14 | let shipping = data.shipping || 'USA'; 15 | let now = Date.now(); 16 | let twentyFourHours = 24 * 60 * 60 * 1000; // 24 hours in milliseconds 17 | if (!lastFetch || now - lastFetch > twentyFourHours) { 18 | // Rates are more than 24 hours old or don't exist, fetch them 19 | fetch('https://open.er-api.com/v6/latest/USD') 20 | .then(response => response.json()) 21 | .then(data => { 22 | rates = data.rates; // Extract the rates from the response 23 | chrome.storage.sync.set({ rates: rates, lastFetch: now }, function () { 24 | executeScript(tabId, taxRate, currency, rates, shippingCost, shipping, listenerSet); 25 | }); 26 | }); 27 | } else { 28 | // Rates are less than 24 hours old, use them 29 | executeScript(tabId, taxRate, currency, rates, shippingCost, shipping); 30 | } 31 | }); 32 | } 33 | }); 34 | 35 | 36 | 37 | 38 | 39 | function executeScript(tabId, taxRate, currency, rates, shippingCost, shipping) { 40 | chrome.scripting.executeScript({ 41 | target: { tabId: tabId }, 42 | function: function (taxRate, currency, rates, shippingCost, shipping) { 43 | 44 | function getItemPrice(item) { 45 | let price; 46 | 47 | if (item <= 50) { 48 | price = 5.99; 49 | } else if (item <= 250) { 50 | price = 15.99; 51 | } else if (item <= 483) { 52 | price = 17.99; 53 | } else if (item < 920) { 54 | price = 19.99; 55 | } else if (item <= 1909) { 56 | price = 24.99; 57 | } else { 58 | price = 29.99; 59 | } 60 | 61 | return price; 62 | } 63 | 64 | function currencySymbol(currency) { 65 | switch (currency) { 66 | case 'USD': 67 | return '$'; 68 | case 'EUR': 69 | return '€'; 70 | case 'GBP': 71 | return '£'; 72 | default: 73 | return currency + " "; 74 | } 75 | } 76 | 77 | function convertCurrency(amount, currency, rates) { 78 | let rate = rates[currency]; 79 | return amount * rate; 80 | } 81 | 82 | let data = [] 83 | let variantRadiosElement = document.querySelector('variant-radios'); 84 | 85 | if (variantRadiosElement) { 86 | let scriptElement = variantRadiosElement.querySelector('script[type="application/json"]'); 87 | let jsonText = scriptElement.textContent; 88 | data = JSON.parse(jsonText); 89 | 90 | // Rest of your code... 91 | 92 | } 93 | 94 | 95 | function replacePrices() { 96 | 97 | let defaultSize = document.querySelector('input.product-variant-size:checked, input.ColorSwatch__Radio:checked'); 98 | let defaultSizeTitle = defaultSize ? defaultSize.value : ''; 99 | let defaultSizeItem = data.find(item => item.title == defaultSizeTitle); 100 | 101 | if (defaultSizeItem) { 102 | console.log("Weight of default selected item: ", defaultSizeItem.weight); 103 | shippingCost = getItemPrice(defaultSizeItem.weight); // Update the shipping cost based on the default size 104 | } 105 | 106 | let priceSpans = document.querySelectorAll('.money'); 107 | priceSpans.forEach(priceSpan => { 108 | let appendedSpans = priceSpan.parentNode.querySelectorAll('.appended'); 109 | appendedSpans.forEach(span => span.remove()); 110 | if (priceSpan) { 111 | let originalPrice = parseFloat(priceSpan.getAttribute('data-original-price')); 112 | if (isNaN(originalPrice)) { 113 | originalPrice = parseFloat(priceSpan.textContent.replace(/[^\d.-]/g, '')); 114 | priceSpan.setAttribute('data-original-price', originalPrice); 115 | } 116 | let convertedPrice = convertCurrency(originalPrice, currency, rates); 117 | let shippingCostConverted = convertCurrency(shippingCost, currency, rates); 118 | 119 | let taxAmount = 0; 120 | let costBeforeTax = convertedPrice; 121 | 122 | if (shipping === 'USA') { 123 | taxAmount = costBeforeTax * taxRate / 100; 124 | } 125 | 126 | costBeforeTax += shippingCostConverted; 127 | 128 | if (shipping === 'EU') { 129 | taxAmount = costBeforeTax * taxRate / 100; 130 | } 131 | 132 | let totalCost = costBeforeTax + taxAmount; 133 | 134 | priceSpan.textContent = `${currencySymbol(currency)}${convertedPrice.toFixed(2)}`; 135 | 136 | if (shippingCost == 0) { 137 | 138 | } else { 139 | let shippingSpan = document.createElement("span"); 140 | shippingSpan.className = 'appended'; 141 | shippingSpan.textContent = ` (+ Shipping ${currencySymbol(currency)}${shippingCostConverted.toFixed(2)})`; 142 | priceSpan.parentNode.appendChild(shippingSpan); 143 | } 144 | 145 | if (taxAmount == 0 || shipping === "No TAX") { 146 | 147 | 148 | } else { 149 | let taxSpan = document.createElement("span"); 150 | taxSpan.className = 'appended'; 151 | taxSpan.textContent = ` (Tax: ${currencySymbol(currency)}${taxAmount.toFixed(2)})`; 152 | priceSpan.parentNode.appendChild(taxSpan); 153 | } 154 | 155 | let totalSpan = document.createElement("span"); 156 | totalSpan.className = 'appended'; 157 | totalSpan.textContent = ` (Total: ${currencySymbol(currency)}${totalCost.toFixed(2)})`; 158 | priceSpan.parentNode.appendChild(totalSpan); 159 | } 160 | }); 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | setupSizeChangeListeners(taxRate, currency, rates, data); 171 | } 172 | 173 | 174 | 175 | function setupSizeChangeListeners(taxRate, currency, rates, data) { 176 | // Get all size selection radio buttons 177 | let sizeRadioButtons = document.querySelectorAll('.product-variant-size, .ColorSwatch__Radio'); 178 | 179 | // Add an event listener to each radio button 180 | sizeRadioButtons.forEach(button => { 181 | // Check if the event listener has already been added 182 | if (!button.hasAttribute('data-listener-set')) { 183 | button.addEventListener('change', () => { 184 | // When a size option is selected, wait a short moment to allow the site to update the price, 185 | // then replace the prices 186 | let matchedItem = data.find(item => item.title == button.value); 187 | 188 | // If a match is found, log the weight 189 | if (matchedItem) { 190 | shippingCost = getItemPrice(matchedItem.weight); 191 | } 192 | 193 | setTimeout(() => { 194 | replacePrices(taxRate, currency, rates) 195 | }, 750); 196 | }); 197 | 198 | // Add a marker to indicate the event listener has been added 199 | button.setAttribute('data-listener-set', true); 200 | } 201 | }); 202 | } 203 | 204 | 205 | 206 | 207 | replacePrices(); 208 | }, 209 | args: [taxRate, currency, rates, shippingCost, shipping] 210 | }); 211 | } -------------------------------------------------------------------------------- /popup/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | LTT.com Real Price 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 221 |
222 | 223 | 224 | 225 | 226 | --------------------------------------------------------------------------------