diff --git a/script.user.js b/script.user.js new file mode 100644 index 0000000..7f84ff1 --- /dev/null +++ b/script.user.js @@ -0,0 +1,239 @@ +// ==UserScript== +// @name RuneScape Wiki Ely Prices +// @namespace https://ely.gg/ +// @version 1.0.0 +// @description Show Ely prices on RuneScape Wiki pages +// @match https://runescape.wiki/w/* +// @grant GM_xmlhttpRequest +// @connect www.ely.gg +// @connect gist.yorgei.dev +// ==/UserScript== + +(async function () { + const dataUrl = 'https://git.yorgei.dev/yorgei/rs-wiki-ely/raw/branch/main/new_data.json'; + + function gmFetchJson(url) { + return new Promise((resolve, reject) => { + GM_xmlhttpRequest({ + method: 'GET', + url, + onload: res => { + try { + const json = JSON.parse(res.responseText); + resolve(json); + } catch (e) { + reject(e); + } + }, + onerror: err => reject(err) + }); + }); + } + + async function fetchPriceData(itemId) { + const url = `https://www.ely.gg/chart/${itemId}/prices`; + const data = await gmFetchJson(url); + return data; + } + + try { + const pageTitleElement = document.querySelector('.mw-page-title-main'); + if (!pageTitleElement) return; + + const originalCursor = pageTitleElement.style.cursor; + + const dataResponse = await fetch(dataUrl); + const itemData = await dataResponse.json(); + + const pageTitle = pageTitleElement.textContent.trim(); + const urlPath = window.location.pathname; + const urlTitle = urlPath.replace('/w/', '').replace(/_/g, ' '); + + let itemId = null; + + if (itemData[pageTitle]) { + itemId = itemData[pageTitle]; + } else if (itemData[urlTitle]) { + itemId = itemData[urlTitle]; + } else { + for (const [itemName, id] of Object.entries(itemData)) { + const itemNameBase = itemName.split('(')[0].trim(); + const lowerItem = itemName.toLowerCase(); + const lowerBase = itemNameBase.toLowerCase(); + const lowerTitle = pageTitle.toLowerCase(); + const lowerUrlTitle = urlTitle.toLowerCase(); + if ( + lowerItem === lowerTitle || + lowerItem === lowerUrlTitle || + lowerBase === lowerTitle || + lowerBase === lowerUrlTitle + ) { + itemId = id; + break; + } + } + } + + if (!itemId) return; + + try { + const priceData = await fetchPriceData(itemId); + if (!priceData.items || !priceData.items.length) return; + + const lastItem = priceData.items[priceData.items.length - 1]; + const price = Number(lastItem.price).toLocaleString(); + const date = new Date(lastItem.date).toLocaleDateString(); + const saleType = String(lastItem.purchase || '').toLowerCase(); + let saleTypeShort = saleType; + if (saleType === 'sold') { + saleTypeShort = 'inb'; + } else if (saleType === 'bought') { + saleTypeShort = 'ins'; + } + + const priceDisplay = document.createElement('span'); + priceDisplay.textContent = ` (${price} gp - ${saleTypeShort} - ${date})`; + priceDisplay.style.color = '#5a8c5a'; + priceDisplay.style.fontWeight = 'bold'; + priceDisplay.style.fontSize = '0.9em'; + + pageTitleElement.appendChild(priceDisplay); + + pageTitleElement.style.cursor = 'pointer'; + pageTitleElement.addEventListener('click', async () => { + try { + const latestPriceData = await fetchPriceData(itemId); + if (latestPriceData.items && latestPriceData.items.length > 0) { + showSalesPopup(latestPriceData.items, itemId, pageTitleElement, originalCursor); + } else { + window.open(`https://www.ely.gg/view_item/${itemId}`, '_blank'); + } + } catch (e) { + window.open(`https://www.ely.gg/view_item/${itemId}`, '_blank'); + } + }); + } catch (e) { + const idDisplay = document.createElement('span'); + idDisplay.textContent = ` (ID: ${itemId}) | Failed to get price.`; + idDisplay.style.color = '#5a8c5a'; + idDisplay.style.fontWeight = 'bold'; + idDisplay.style.fontSize = '0.9em'; + pageTitleElement.appendChild(idDisplay); + } + } catch (e) { + console.error('Error loading Ely userscript data:', e); + } + + function showSalesPopup(items, itemId, pageTitleElement, originalCursor) { + const existingPopup = document.getElementById('ely-sales-popup'); + if (existingPopup) { + existingPopup.remove(); + } + + const popup = document.createElement('div'); + popup.id = 'ely-sales-popup'; + popup.style.position = 'fixed'; + popup.style.top = '50%'; + popup.style.left = '50%'; + popup.style.transform = 'translate(-50%, -50%)'; + popup.style.backgroundColor = '#fff'; + popup.style.border = '1px solid #ccc'; + popup.style.borderRadius = '8px'; + popup.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)'; + popup.style.padding = '20px'; + popup.style.zIndex = '10000'; + popup.style.maxWidth = '500px'; + popup.style.width = '90%'; + popup.style.maxHeight = '70vh'; + popup.style.overflowY = 'auto'; + + const header = document.createElement('h3'); + header.textContent = 'Recent Sales'; + header.style.marginTop = '0'; + header.style.marginBottom = '15px'; + header.style.color = '#333'; + popup.appendChild(header); + + const salesList = document.createElement('div'); + salesList.style.marginBottom = '20px'; + + const recentSales = items.slice(-10).reverse(); + + recentSales.forEach(sale => { + const saleItem = document.createElement('div'); + saleItem.style.display = 'flex'; + saleItem.style.justifyContent = 'space-between'; + saleItem.style.padding = '8px 0'; + saleItem.style.borderBottom = '1px solid #eee'; + + const price = document.createElement('span'); + price.textContent = `${parseInt(sale.price, 10).toLocaleString()} gp`; + price.style.fontWeight = 'bold'; + + const type = document.createElement('span'); + const purchaseLower = String(sale.purchase || '').toLowerCase(); + type.textContent = purchaseLower === 'sold' ? 'inb' : 'ins'; + type.style.color = purchaseLower === 'sold' ? '#d9534f' : '#5cb85c'; + type.style.fontWeight = 'bold'; + + const date = document.createElement('span'); + date.textContent = new Date(sale.date).toLocaleDateString(); + date.style.color = '#666'; + + saleItem.appendChild(price); + saleItem.appendChild(type); + saleItem.appendChild(date); + salesList.appendChild(saleItem); + }); + + popup.appendChild(salesList); + + const buttonContainer = document.createElement('div'); + buttonContainer.style.display = 'flex'; + buttonContainer.style.justifyContent = 'space-between'; + buttonContainer.style.marginTop = '10px'; + + const elyButton = document.createElement('button'); + elyButton.textContent = 'Go to Ely'; + elyButton.style.backgroundColor = '#5a8c5a'; + elyButton.style.color = 'white'; + elyButton.style.border = 'none'; + elyButton.style.padding = '8px 16px'; + elyButton.style.borderRadius = '4px'; + elyButton.style.cursor = 'pointer'; + elyButton.addEventListener('click', () => { + window.open(`https://www.ely.gg/view_item/${itemId}`, '_blank'); + popup.remove(); + pageTitleElement.style.cursor = originalCursor; + }); + + const closeButton = document.createElement('button'); + closeButton.textContent = 'Close'; + closeButton.style.backgroundColor = '#6c757d'; + closeButton.style.color = 'white'; + closeButton.style.border = 'none'; + closeButton.style.padding = '8px 16px'; + closeButton.style.borderRadius = '4px'; + closeButton.style.cursor = 'pointer'; + closeButton.addEventListener('click', () => { + popup.remove(); + pageTitleElement.style.cursor = originalCursor; + }); + + buttonContainer.appendChild(elyButton); + buttonContainer.appendChild(closeButton); + popup.appendChild(buttonContainer); + + document.body.appendChild(popup); + + function closePopupOnOutsideClick(e) { + if (!popup.contains(e.target) && e.target !== pageTitleElement) { + popup.remove(); + document.removeEventListener('click', closePopupOnOutsideClick); + pageTitleElement.style.cursor = originalCursor; + } + } + + document.addEventListener('click', closePopupOnOutsideClick); + } + })(); \ No newline at end of file