commit e23ac642a73f1af75c8b448e510f7ec87f310100 Author: Yorgei Date: Sun Jan 18 14:29:12 2026 +1000 init diff --git a/.gitea/workflows/update_data.yaml b/.gitea/workflows/update_data.yaml new file mode 100644 index 0000000..815b5b4 --- /dev/null +++ b/.gitea/workflows/update_data.yaml @@ -0,0 +1,42 @@ +name: Update Data +on: + schedule: + - cron: '0 */6 * * *' + workflow_dispatch: + +jobs: + update-data: + runs-on: ubuntu-latest + container: + image: nikolaik/python-nodejs:python3.12-nodejs22-slim + steps: + - name: Install system dependencies + run: | + apt-get update + apt-get install -y git + + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + + - name: Run download script + run: python download_data.py + + - name: Check for changes and commit + run: | + git config --global user.name 'Gitea Actions' + git config --global user.email 'actions@noreply.gitea.io' + + # Check if new_data.json has changed + if [[ -n $(git status -s chrome-extension/new_data.json) ]]; then + echo "Changes detected in new_data.json" + git add chrome-extension/new_data.json + git commit -m "Auto-update new_data.json" + git push + else + echo "No changes detected" + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c98053 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +response.html \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bdaf28 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# RuneScape Wiki Ely Prices + +This extension integrates Ely.gg price data directly into the official RuneScape Wiki, allowing players to view real-time market information seamlessly while browsing data. + +## Description + +Enhance your RuneScape Wiki experience with live pricing data. This extension fetches the latest street prices from Ely.gg and displays them right next to the item title on the Wiki page. It helps you stay informed about the current market value, whether you are checking for an upgrade or planning your next flip. + +## Features + +* **Live Price Display**: Shows the most recent transaction price, including whether it was an Instant Buy (inb) or Instant Sell (ins), and the date of the transaction. +* **Sales History Popup**: Click on the price to open a details popup showing the last 10 recorded sales for that item. +* **Seamless Integration**: Designed to look optimal on the Wiki without cluttering the interface. +* **Custom Data Source**: Includes an options menu to configure a custom data URL if needed. + +## Privacy + +This extension does not collect any personal data. It only fetches public price information corresponding to the Wiki page you are currently viewing. diff --git a/build_release.py b/build_release.py new file mode 100644 index 0000000..0b7a4a3 --- /dev/null +++ b/build_release.py @@ -0,0 +1,37 @@ +import os +import zipfile +import shutil +import json + +def create_zip(source_dir, output_filename, manifest_filename='manifest.json'): + with zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: + for root, dirs, files in os.walk(source_dir): + for file in files: + if file.startswith('manifest') and file.endswith('.json'): + continue + + file_path = os.path.join(root, file) + arcname = os.path.relpath(file_path, source_dir) + zipf.write(file_path, arcname) + + manifest_path = os.path.join(source_dir, manifest_filename) + zipf.write(manifest_path, 'manifest.json') + +def main(): + if os.path.exists('release'): + shutil.rmtree('release') + os.makedirs('release') + + # Userscript + shutil.copy('userscript.js', 'release/ely-userscript.user.js') + + # Chrome Extension (Manifest V3) + create_zip('chrome-extension', 'release/ely-extension-chrome.zip', 'manifest-v3.json') + + # Firefox Extension (Manifest V2) + create_zip('chrome-extension', 'release/ely-extension-firefox.zip', 'manifest.json') + + print("Build complete in /release folder.") + +if __name__ == "__main__": + main() diff --git a/chrome-extension/background.js b/chrome-extension/background.js new file mode 100644 index 0000000..ee5777f --- /dev/null +++ b/chrome-extension/background.js @@ -0,0 +1,35 @@ +// CORS +chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === 'fetchPrice') { + fetch(`https://www.ely.gg/chart/${request.itemId}/prices`) + .then(response => response.json()) + .then(data => sendResponse({ success: true, data })) + .catch(error => sendResponse({ success: false, error: error.message })); + return true; + } else if (request.action === 'fetchData') { + fetch(request.url) + .then(response => response.json()) + .then(data => sendResponse({ success: true, data })) + .catch(error => sendResponse({ success: false, error: error.message })); + return true; + } +}); + +//Firefox compatibility +if (typeof browser !== 'undefined') { + browser.runtime.onMessage.addListener((request, sender, sendResponse) => { + if (request.action === 'fetchPrice') { + fetch(`https://www.ely.gg/chart/${request.itemId}/prices`) + .then(response => response.json()) + .then(data => sendResponse({ success: true, data })) + .catch(error => sendResponse({ success: false, error: error.message })); + return true; + } else if (request.action === 'fetchData') { + fetch(request.url) + .then(response => response.json()) + .then(data => sendResponse({ success: true, data })) + .catch(error => sendResponse({ success: false, error: error.message })); + return true; + } + }); +} diff --git a/chrome-extension/content.js b/chrome-extension/content.js new file mode 100644 index 0000000..b718873 --- /dev/null +++ b/chrome-extension/content.js @@ -0,0 +1,257 @@ +(async function() { + const browserAPI = typeof browser !== 'undefined' ? browser : chrome; + try { + const getStorage = (key) => { + return new Promise((resolve) => { + const api = (typeof chrome !== 'undefined' && chrome.storage) ? chrome : browserAPI; + if (api.storage && api.storage.sync) { + api.storage.sync.get([key], (result) => { + resolve(result ? result[key] : null); + }); + } else { + resolve(null); + } + }); + }; + + const sendMessage = (message) => { + return new Promise((resolve) => { + const api = (typeof chrome !== 'undefined' && chrome.runtime) ? chrome : browserAPI; + try { + api.runtime.sendMessage(message, (response) => { + // Chrome callback + if (api.runtime.lastError) { + resolve(null); + } else { + resolve(response); + } + }); + + } catch(e) { + if (browserAPI && browserAPI.runtime && browserAPI.runtime.sendMessage) { + browserAPI.runtime.sendMessage(message).then(resolve).catch(() => resolve(null)); + } else { + resolve(null); + } + } + }); + }; + + const customUrl = await getStorage('customDataUrl'); + let itemData; + + if (customUrl) { + const response = await sendMessage({ + action: 'fetchData', + url: customUrl + }); + if (response && response.success) { + itemData = response.data; + } else { + console.error('Failed to fetch custom data, falling back to local'); + const localResponse = await fetch(browserAPI.runtime.getURL('new_data.json')); + itemData = await localResponse.json(); + } + } else { + const response = await fetch(browserAPI.runtime.getURL('new_data.json')); + itemData = await response.json(); + } + + const pageTitleElement = document.querySelector('.mw-page-title-main'); + if (!pageTitleElement) return; + + const originalCursor = pageTitleElement.style.cursor; + + const pageTitle = pageTitleElement.textContent.trim(); + + let itemId = null; + + if (itemData[pageTitle]) { + itemId = itemData[pageTitle]; + } else { + const urlPath = window.location.pathname; + const urlTitle = urlPath.replace('/w/', '').replace(/_/g, ' '); + + if (itemData[urlTitle]) { + itemId = itemData[urlTitle]; + } else { + for (const [itemName, id] of Object.entries(itemData)) { + const itemNameBase = itemName.split('(')[0].trim(); + if (itemName.toLowerCase() === pageTitle.toLowerCase() || + itemName.toLowerCase() === urlTitle.toLowerCase() || + itemNameBase.toLowerCase() === pageTitle.toLowerCase() || + itemNameBase.toLowerCase() === urlTitle.toLowerCase()) { + itemId = id; + break; + } + } + } + } + + if (itemId) { + try { + const response = await browserAPI.runtime.sendMessage({ + action: 'fetchPrice', + itemId: itemId + }); + + if (response.success && response.data.items && response.data.items.length > 0) { + const lastItem = response.data.items[response.data.items.length - 1]; + const price = lastItem.price.toLocaleString(); + const date = new Date(lastItem.date).toLocaleDateString(); + const saleType = lastItem.purchase; + var saleTypeShort = saleType; + if (saleType.toLowerCase() === "sold") { + saleTypeShort = "inb" + } else if (saleType.toLowerCase() === "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); + } + } catch (priceError) { + console.error('Error fetching price data:', priceError); + + 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); + } + + pageTitleElement.style.cursor = 'pointer'; + pageTitleElement.addEventListener('click', async () => { + try { + const response = await sendMessage({ + action: 'fetchPrice', + itemId: itemId + }); + + if (response.success && response.data.items && response.data.items.length > 0) { + showSalesPopup(response.data.items, itemId); + } + } catch (error) { + console.error('Error fetching sales data:', error); + window.open(`https://www.ely.gg/view_item/${itemId}`, '_blank'); + } + }); + } + } catch (error) { + console.error('Error loading item data:', error); + } + + function showSalesPopup(items, itemId) { + 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).toLocaleString()} gp`; + price.style.fontWeight = 'bold'; + + const date = document.createElement('span'); + date.textContent = new Date(sale.date).toLocaleDateString(); + date.style.color = '#666'; + + const type = document.createElement('span'); + type.textContent = sale.purchase.toLowerCase() === 'sold' ? 'inb' : 'ins'; + type.style.color = sale.purchase === 'sold' ? '#d9534f' : '#5cb85c'; + type.style.fontWeight = 'bold'; + + 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(); + }); + + 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(); + }); + + buttonContainer.appendChild(elyButton); + buttonContainer.appendChild(closeButton); + popup.appendChild(buttonContainer); + + document.body.appendChild(popup); + + document.addEventListener('click', function closePopup(e) { + if (!popup.contains(e.target) && e.target !== pageTitleElement) { + popup.remove(); + document.removeEventListener('click', closePopup); + } + }); + } +})(); diff --git a/chrome-extension/img/128.png b/chrome-extension/img/128.png new file mode 100644 index 0000000..f95171b Binary files /dev/null and b/chrome-extension/img/128.png differ diff --git a/chrome-extension/img/64.png b/chrome-extension/img/64.png new file mode 100644 index 0000000..0a432f3 Binary files /dev/null and b/chrome-extension/img/64.png differ diff --git a/chrome-extension/manifest-firefox.json b/chrome-extension/manifest-firefox.json new file mode 100644 index 0000000..38d4880 --- /dev/null +++ b/chrome-extension/manifest-firefox.json @@ -0,0 +1,38 @@ +{ + "manifest_version": 2, + "name": "RS Wiki Ely.gg Price Display", + "version": "1.0", + "description": "Displays item IDs from ely.gg on RuneScape Wiki pages", + "permissions": [ + "storage", + "https://www.ely.gg/*" + ], + "icons": { + "48": "img/64.png", + "96": "img/128.png" + }, + "browser_action": { + "default_icon": "img/64.png", + "default_title": "Configure Ely Extension", + "default_popup": "options.html" + }, + "background": { + "scripts": [ + "background.js" + ] + }, + "content_scripts": [ + { + "matches": [ + "https://runescape.wiki/*" + ], + "js": [ + "content.js" + ], + "run_at": "document_idle" + } + ], + "web_accessible_resources": [ + "new_data.json" + ] +} \ No newline at end of file diff --git a/chrome-extension/manifest-v3.json b/chrome-extension/manifest-v3.json new file mode 100644 index 0000000..d3b0e34 --- /dev/null +++ b/chrome-extension/manifest-v3.json @@ -0,0 +1,51 @@ +{ + "manifest_version": 3, + "name": "RS Wiki Ely.gg Price Display", + "version": "1.0", + "description": "Displays item IDs from ely.gg on RuneScape Wiki pages", + "permissions": [ + "storage" + ], + "host_permissions": [ + "https://www.ely.gg/*", + "http://*/*", + "https://*/*" + ], + "icons": { + "48": "img/64.png", + "96": "img/128.png" + }, + "action": { + "default_icon": "img/64.png", + "default_title": "Configure Ely Extension", + "default_popup": "options.html" + }, + "background": { + "service_worker": "background.js" + }, + "content_scripts": [ + { + "matches": [ + "https://runescape.wiki/*" + ], + "js": [ + "content.js" + ], + "run_at": "document_idle" + } + ], + "web_accessible_resources": [ + { + "resources": [ + "new_data.json" + ], + "matches": [ + "https://runescape.wiki/*" + ] + } + ], + "options_ui": { + "page": "options.html", + "open_in_tab": false + } +} \ No newline at end of file diff --git a/chrome-extension/manifest.json b/chrome-extension/manifest.json new file mode 100644 index 0000000..89b8ee5 --- /dev/null +++ b/chrome-extension/manifest.json @@ -0,0 +1,44 @@ +{ + "manifest_version": 2, + "name": "RS Wiki Ely.gg Price Display", + "version": "1.0", + "description": "Displays item IDs from ely.gg on RuneScape Wiki pages", + "permissions": [ + "storage", + "https://www.ely.gg/*", + "http://*/*", + "https://*/*" + ], + "icons": { + "48": "img/64.png", + "96": "img/128.png" + }, + "browser_action": { + "default_icon": "img/64.png", + "default_title": "Configure Ely Extension", + "default_popup": "options.html" + }, + "background": { + "scripts": [ + "background.js" + ] + }, + "content_scripts": [ + { + "matches": [ + "https://runescape.wiki/*" + ], + "js": [ + "content.js" + ], + "run_at": "document_idle" + } + ], + "web_accessible_resources": [ + "new_data.json" + ], + "options_ui": { + "page": "options.html", + "open_in_tab": false + } +} \ No newline at end of file diff --git a/chrome-extension/new_data.json b/chrome-extension/new_data.json new file mode 100644 index 0000000..56c1e26 --- /dev/null +++ b/chrome-extension/new_data.json @@ -0,0 +1,1090 @@ +{ + "White Partyhat": 1, + "Yellow Partyhat": 2, + "Purple Partyhat": 3, + "Red Partyhat": 4, + "Christmas Scythe": 5, + "Loved Up Walk Override": 6, + "Assassin Walk Override Token": 9, + "Party fever Walk Override Token": 10, + "Conga Dance Override Token": 11, + "Treasure Dive Teleport Token": 12, + "Sand Dive Teleport Token": 13, + "Mining Away Teleport Token": 14, + "Rainbow Teleport Token": 15, + "Stocking Teleport Token": 17, + "Bucking Yak Teleport Token": 18, + "Christmas Lootbeam Token": 19, + "Summer Prize Token": 20, + "Buddy Pet Token": 22, + "Zoltan Pet Token": 23, + "Seahorse Follower Pet Token": 24, + "Starfish Follower Pet Token": 25, + "Pufferfish Follower Pet Token": 26, + "Banana Boat Mount Token": 27, + "Dizzy Stick Token": 28, + "Fish in a Bag Token": 29, + "Zoltan Plushie Token": 30, + "Stack of Presents Token": 31, + "Penguin Plush Token": 32, + "Mammoth Plush Token": 33, + "Lederhosen Terrorbird Mount Token": 35, + "Bubble Blower Token": 36, + "Yak Plushie Token": 37, + "Yak Balloon Token": 38, + "Luchador Mask Token": 39, + "Novtumberfest Dance Emotes Token": 42, + "Test of Strength Emote token": 43, + "Zarosian Apron Token": 46, + "Vegetable Apron Token": 47, + "Beach Apron Token": 48, + "Crustacea Armour Token": 49, + "Meditation Rest Animation Token": 52, + "Hacky Sack Resting Emote Token": 53, + "Sand Dunk Resting Emote Token": 54, + "Contact Juggling Resting Token": 55, + "Palm Tree Rest Emote Token": 56, + "Carrying Steins Resting Token": 57, + "Sandy Sandwich Rest Override Token": 58, + "Cocktail Flare Rest Override Token": 59, + "Snowman Building Rest Token": 60, + "Shade Thrower Rest Token": 61, + "Novtumberfest Outfit Token": 62, + "Elf Shoes Token": 63, + "Dancer Outfit Token": 64, + "Crown of Seasons": 65, + "Cloak of Seasons": 66, + "Chest of Seasons": 67, + "Glove of Seasons": 69, + "Boots of Seasons": 70, + "Pet of Seasons": 71, + "Santa Claws Token": 72, + "Glacial Shieldbow Token": 73, + "Dizzy Teleport Token": 16, + "Santa Paws Token": 76, + "Snow Parasol": 77, + "Snow Cape": 78, + "Black Santa Hat": 79, + "Christmas Cracker": 84, + "Easter Egg": 85, + "Pumpkin": 86, + "Disk of Returning": 87, + "Half Jug Wine": 88, + "Green Partyhat": 89, + "Blue Partyhat": 90, + "Rainbow Wand": 92, + "Selfie Emote Token": 41, + "Red Santa Hat": 80, + "Zombie Walk Override Token": 50, + "OG Gem Cape Token": 51, + "Red Halloween Mask": 83, + "Blue Halloween Mask": 82, + "Green Halloween Mask": 81, + "Crab Hat": 91, + "Party Hat Jumper": 75, + "Bottom of Seasons": 68, + "Snowverload Plush Token": 34, + "Rainbow Scythe": 93, + "Rainbow Pet Token": 94, + "Infernal Cerberus faulds token": 312, + "Plague Walk Override Token": 7, + "Rainbow Parasol": 95, + "Rainbow Gaze": 96, + "Clover Parasol": 97, + "Surfboard Shield Token": 98, + "Ink Shooter Token": 99, + "Tribal Pet Token": 100, + "Snowman Pet Token": 101, + "Christmas Tree Hat": 102, + "Fish Mask": 103, + "Shadow Gem Sack Token": 104, + "Shadow Gem Cape Token": 105, + "Shadow Gem Necklace Token": 106, + "Shadow Gem Crown Token": 107, + "Hot Sand Walk Override Token": 8, + "Bone Master Outfit Token": 112, + "Earhart the penguin token": 114, + "Rainbow Cape": 115, + "Tomb Gorilla Pet Token": 116, + "Arthur Pet Token": 117, + "Skeletal Bear Pet Token": 118, + "Clawdia Claws Token": 119, + "Keg Pet Token": 122, + "Christmas Tree Cape": 123, + "Present Sack Token": 124, + "Present Hammer Token": 125, + "Holly Wreath": 126, + "OG Gem Crown Token": 108, + "Rainbow Amulet": 127, + "Duck Ring Token": 120, + "Goebie Backpack Token": 128, + "Sandcastle Pet Token": 129, + "Octopus Pet Token": 130, + "Carrot Lance Token": 131, + "Cottontail Legs Token": 132, + "Cottontail Top token": 133, + "Cottontail Helmet Token": 134, + "Forsaken Graahk Pet Token": 135, + "Crypt Scythe Token": 136, + "Crypt Staff Token": 137, + "Crypt Shieldbow Token": 138, + "Hook a Duck Flail Token": 139, + "Venturer Outfit Token": 140, + "Menowin Outfit Token": 141, + "Mallet Token": 151, + "Crystal Ball Token": 152, + "Pickaxe Hat Token": 153, + "Face Paint Token": 154, + "Easter Egg Hat Token": 142, + "Robin": 143, + "Woolly Pudding Hat": 144, + "Starfish Balloon": 145, + "Pufferfish Balloon": 146, + "Seahorse Balloon": 147, + "Beach Armour Token": 148, + "Pufferfish Launcher Token": 149, + "Crusty Pet Token": 150, + "Sandy Maul Override Token": 155, + "Sandy 2h Sword Token": 156, + "Sandy Club Token": 157, + "Mint Hair Head Token": 158, + "Strawberry Hair Head Token": 159, + "Vanilla Hair Head Token": 160, + "Conga Eel Whip Token": 161, + "Ice Lolly Wand Token": 162, + "Shark Fin Token": 163, + "Lifeguard Chair Head Token": 164, + "Kauai Parasol Token": 165, + "Oahu Parasol Token": 166, + "Kahului Parasol Token": 167, + "Maui Parasol Token": 168, + "Hawaii Parasol Token": 169, + "Pyramid Hat Head Token": 170, + "Coral Sword Token": 171, + "Coral Dagger Token": 172, + "Phoebe Pet Token": 173, + "Gillbert Pet Token": 174, + "Snorkel Token": 175, + "Throwing Starfish Token": 176, + "Clawdia Hat Token": 177, + "Dragon Ring Token": 178, + "Stick Of Rock Token": 179, + "Rubber Turkey": 180, + "Off-hand Rubber Turkey": 181, + "Clawdia Wings Token": 182, + "Ocean Archer's Helm": 183, + "Ocean's Archer Body": 184, + "Ocean's Archer Legs": 185, + "Ocean's Archer Bow": 186, + "OG Gem Necklace Token": 110, + "OG Gem Sack Token": 109, + "Wolpertinger Pet Token": 121, + "Ocean's Archer Crossbow": 187, + "Cerberus Pet Token": 188, + "Cerberus Boots Token": 189, + "Shadowy Egg": 313, + "Cerberus Breastplate Token": 190, + "Cerberus Faulds Token": 191, + "Cerberus Gloves Token": 192, + "Cerberus Helmet Token": 193, + "Meowsketeer's Hat Token": 194, + "Meowsketeer's Tunic Token": 195, + "Meowsketeer's Trousers Token": 196, + "Meowsketeer's Gloves Token": 197, + "Meowsketeer's Boots Token": 198, + "Meowsketeer's Scarf Token": 199, + "Meowsketeer's Rapier Token": 200, + "Sameowrai's Helmet Token": 201, + "Sameowrai's Breastplate Token": 202, + "Sameowrai's Faulds Token": 203, + "Sameowrai's Gauntlets Token": 204, + "Sameowrai's Tabi Token": 205, + "Sameowrai's Bow Token": 206, + "Sameowrai's Cata-Nya Token": 207, + "Blue Shorthair Fur Token": 208, + "Phoenix Aura Token": 210, + "Phoenix Wing Backpack Token": 211, + "Christmas Tree Jumper": 74, + "Present head token": 214, + "Terrorbird Plushie": 212, + "Christmas Tree Kite": 213, + "Phoenix Mimic Pet Token": 215, + "Shadow Gem Helmet": 216, + "Christmas Penguin Jumper": 217, + "Wreath Shield Token": 218, + "Rainbow Bow Token": 219, + "Rainbow Aura": 263, + "Treasure Resting Token": 220, + "Beer Goggles Token": 225, + "Gingerbread Necklace Token": 224, + "Stein Weapon Token": 226, + "Shark bait token": 227, + "Fortune Cape Token": 228, + "Wreath Crown Token": 229, + "Water Balloon Launcher": 230, + "Bucky Token": 231, + "Clover Wand Token": 232, + "Clover Staff Token": 234, + "Christmas Pudding Balloon": 235, + "Squeaker Axe Token": 236, + "Bloodtusk Warlord Helmet": 237, + "Bloodtusk Warlord Upper Body": 238, + "Bloodtusk Warlord Lower Body": 239, + "Cadavaberry Parasol": 241, + "Coconut parasol": 242, + "Dwellberry parasol": 243, + "Lime parasol": 245, + "Orange parasol": 246, + "Strawberry parasol": 247, + "Watermelon parasol": 248, + "Apple Parasol": 240, + "Chinchompa Jumper Token": 222, + "Clover Bow Token": 233, + "Guthix Jumper Token": 223, + "Hypnotic parasol Token": 249, + "Lemon parasol": 244, + "Purified Swords": 274, + "Token Index": 265, + "Bond": 259, + "Blood Dye": 252, + "Caller of the Sea Token": 256, + "Fortune Teller Outfit Token": 257, + "Orlando Smith Hat": 258, + "Ice Dye": 255, + "Shadow Dye": 253, + "Rainbow Halo Token": 209, + "Loved Up Rest": 275, + "Shadow Gem Ranged": 260, + "Purified Crossbow": 272, + "Purified Shortbow": 267, + "Purified Wand and Orb": 269, + "Purified Greatsword": 270, + "Purified Staff": 268, + "Purified Halberd": 271, + "Rudolph Necklace Token": 279, + "Purified 2h Crossbow": 266, + "Cerberus Staff Token": 276, + "Cerberus Claw Token": 278, + "Rares Index": 264, + "Third Age Dye": 251, + "Barrows Dye": 254, + "Shadow Gem Melee": 261, + "Clover Axe Token": 273, + "Cerberus Bow Tokwn": 277, + "Shadow Gem Magic": 262, + "Pretzel Shield Token": 221, + "Barrel of Monkeys": 280, + "Beach Ball Token": 281, + "Bucket Head Token": 282, + "Bucket Staff Override Token": 284, + "Blunting Whip Token": 285, + "Tavias Fishing Rod": 297, + "Guildmaster Tony's mattock": 298, + "Hazelmere's Signet Ring": 299, + "Seashell Necklace Tokens": 335, + "Ammonite Necklace Token": 336, + "Rainbow WIngs Token": 318, + "Easter Pet Token (Eggos)": 21, + "Scripture of Jas": 338, + "Staff of Sliske": 321, + "Inquisitor Staff": 322, + "Wand of the Praesul (Praesul Wand)": 323, + "Surfboard Emote Token": 345, + "Throwing Disk Token": 346, + "Clover Sword Token": 286, + "Pot of Gold Token": 287, + "Rei Ti Ronin Bracers": 292, + "Cinderbane Gloves": 351, + "Stephanie Pet Token": 327, + "Beach Towel Outfit Token": 328, + "Essence of Finality": 352, + "Elegant Sun Hat Token": 332, + "Menaphos Beachwear Token": 333, + "Luck of the Dwarves": 354, + "Amulet of Souls": 355, + "Khopesh of Tumeken": 365, + "Greater Concentrated Blast Codex": 339, + "Kerapac Wrist Wraps": 340, + "Deathtouch Bracelet": 356, + "Manuscript of Bik": 342, + "Manuscript of Ful": 343, + "Manuscript of Wen": 344, + "Hexhunter Bow": 357, + "Terrasaur Maul": 358, + "Greater Fury Ability Codex": 359, + "Noxious Longbow": 303, + "Noxious Scythe": 304, + "Noxious Staff": 305, + "Blightbound Crossbow": 306, + "Zaros Godsword": 307, + "Seren Godbow": 309, + "Rei Ti Ronin Faulds": 289, + "Rei Ti Ronin Scarf": 290, + "Rei Ti Nonin Sugegasa": 291, + "Rei Ti Ronin Tunic": 293, + "Pinata Plushie": 294, + "Pinata Sombrero": 295, + "Leveller and Bucket token": 296, + "Buried in Sand Rest": 301, + "Tongue Cape": 302, + "Infernal Cerberus breastplate": 314, + "Infernal Cerberus gloves": 315, + "Infernal Cerberus boots": 316, + "Gnome Scarf": 317, + "Chocolate Hair Head Token": 320, + "Second Age Platebody": 325, + "Second Age Platelegs": 326, + "Eldritch Crossbow": 300, + "Beachball Orb Token": 40, + "Bronzed Sun Hat Token": 330, + "Elysian Spirit Shield": 360, + "Greater Chain Codex": 324, + "Divine Spirit Shield": 361, + "Staff of Armadyl": 337, + "Fractured Armadyl Symbol (Kerapac)": 349, + "Fractured Shaft (Kerapac)": 348, + "Bronzed Sandals Token": 329, + "Manuscript of Jas": 341, + "Magical Eggs": 319, + "Spectral Spirit Shield": 362, + "Menaphos Parasol Token": 334, + "Elegant Sandals Token": 331, + "Arcane Spirit Shield": 363, + "Off-Hand Blightbound Crossbow": 364, + "Masterwork Spear of Annhiliation": 367, + "Dragon Rider Lance": 368, + "Imperium Core": 369, + "Khopesh of Elidinis (Off-Hand Khopesh)": 366, + "Ascension Crossbow": 370, + "Off-Hand Ascension Crossbow": 371, + "Trimmed Mastework Helm": 372, + "Trimmed Masterwork Platebody": 373, + "Trimmed Masterwork Platelegs": 374, + "Fractured Stabilization Gem (Kerapac)": 347, + "Shovel Sword Token": 283, + "trout (test item)": 310, + "Trimmed Masterwork Gloves": 375, + "Trimmed Masterwork Boots": 376, + "Ring of Death": 353, + "Praesul Codex": 377, + "Berserker Ring": 378, + "Ingenuity of the Humans Ability Codex": 379, + "Mazcab Ability Codex": 381, + "Fleeting Boots": 382, + "Greater Flurry Ability Codex": 380, + "Seismic Singularity": 383, + "Seismic Wand": 384, + "Greater Barge Ability Codex": 385, + "Erethdors Grimoire": 386, + "Reprisal Ability Codex": 387, + "Brooch of the Gods": 388, + "Dormant Seren Godbow": 389, + "Divert Ability Codex": 390, + "Eldritch Crossbow Stock": 391, + "Eldritch Crossbow Limb": 392, + "Eldritch Crossbow Mechanism": 393, + "Statius Warhammer": 394, + "Kinetic Cyclone Upgrade Kit": 396, + "Oldak Coil Upgrade Kit": 397, + "Dwarf Multicannon Upgrade Kit": 395, + "Shadow Spike": 398, + "Laniakeas Spear": 399, + "Greater Ricochet Ability Codex": 350, + "Alchemical Hydrix": 400, + "Drygore Longsword": 401, + "Off-hand Drygore Longsword": 402, + "Drygore Rapier": 403, + "Off-Hand Drygore Rapier": 404, + "Torn Grimoire Page": 405, + "Alchemical Onyx": 406, + "Drygore Mace": 407, + "Off-hand Drygore Mace": 408, + "Double Surge Codex": 409, + "Scripture of Wen": 419, + "Nightmare Gauntlets": 418, + "Enchanted Nightmare Gauntlets": 416, + "Enhanced Kerapac's wrist wraps": 415, + "Enhanced Gloves of Passage": 414, + "Croesus Enriched Root": 436, + "Dark Shard of Leng (t95)": 412, + "Dark Ice Shard": 411, + "Infernal Cerberus Pet": 420, + "Dark Ice Sliver": 410, + "Dark Sliver of Leng (t95)": 413, + "Rainbow Outfit Token": 421, + "Primal Pickaxe +5": 1057, + "Cryptbloom Top (Croesus)": 424, + "Cryptbloom Bottoms (Croesus)": 425, + "Cryptbloom Gloves (Croesus)": 426, + "Cryptbloom Boots (Croesus)": 427, + "Croesus Foultorch": 433, + "Croesus Sporehammer": 434, + "Tagga's Corehammer": 437, + "Sana's Fyrtorch": 438, + "Cryptbloom Helm (Cryptbloom Armour)": 423, + "Scripture of Bik": 439, + "Third Age Druidic Cloak": 440, + "Scripture of Ful": 444, + "Obsidian Blade (TzKal-Zuk)": 445, + "Magma Core (TzekHaar Front)": 446, + "Ancient Hilt (TzekHaar Front)": 447, + "Pernix's Quiver": 450, + "Pernix Fragments": 449, + "Golden Partyhat": 451, + "Frosty Cerberus Claws Token": 455, + "Frosty Cerberus Boots Token": 452, + "Frosty Cerberus Bow Token": 453, + "Frosty Cerberus Breastplate Token": 454, + "Frosty Cerberus Faulds Token": 456, + "Frosty Cerberus Gloves Token": 457, + "Frosty Cerberus Helmet Token": 458, + "Frosty Cerberus Pet Token": 459, + "Frosty Cerberus Staff Token": 460, + "Green Santa Hat": 461, + "Frosted Wreath": 463, + "Croesus Spore Sack": 435, + "Magma Tempest Ability Codex": 442, + "Abomination Cape": 441, + "Ek-ZekKil (Zuk Sword)": 443, + "Masterwork 2h sword": 1058, + "Primal 2h sword": 1059, + "Runic attuner": 1060, + "Gift Wrap Scythe": 462, + "Rudolph Jumper": 464, + "Left Banana of Knowledge": 465, + "Right Banana of Knowledge": 466, + "Armadyl Battlestaff": 467, + "Fayre Dancer Emote Pack Two Token": 44, + "Fayre Dancer Emote Pack One Token": 45, + "Plague Rest Override Token": 508, + "Plague Teleport Override Token": 509, + "Flower Hairpin Token": 510, + "Oar Token": 511, + "Iaia Beachwear Outfit Token": 512, + "Golden Roses": 470, + "Fragment of Het": 468, + "Third Age Amulet": 476, + "Second Age Robe Top": 478, + "Second Age Robe Bottom": 479, + "Third Age Vambracers": 489, + "Second Age Range Coif": 491, + "memory dowser": 1061, + "Second Age Range Legs": 487, + "Second Age Range Top": 486, + "Third Age Mage Hat": 485, + "Third Age Coif": 484, + "Third Age Robe Top": 475, + "Third Age Full Helmet": 471, + "Third Age Kiteshield": 474, + "Third Age Platelegs": 473, + "Third Age Platebody": 472, + "Third Age Robe Legs": 477, + "Third Age Druidic Wreath": 488, + "Third Age Rage Top": 483, + "Third Age Range Legs": 482, + "Third Age Druidic Top": 480, + "Third Age Druidic Bottom": 481, + "Second Age Sword": 492, + "Second Age Bow": 493, + "Second Age Staff": 494, + "Rainbow Boquet Wand Token": 495, + "Sceptre of Enchantment": 496, + "Coin of Enchantment": 497, + "Oil of Enchantment": 498, + "Peep the Chick Pet Token": 502, + "Diamond Cane": 504, + "Rainbow Title Scroll": 506, + "Rainbow Glasses": 505, + "Woodland Fox Ears": 500, + "Diamond Title Scroll": 503, + "Woodland Fox Tail": 501, + "Hall of Fame Walk Token": 499, + "Demon Slayer Codex": 507, + "Latent Offering": 1063, + "Manuscript of Elidinis": 1064, + "Chaos Roar ability codex": 520, + "Enchantment of Affliction": 521, + "Enchantment of Agony": 522, + "Enchantment of Dispelling": 523, + "Enchantment of Dread": 524, + "Enchantment of Flames": 525, + "Enchantment of Heroism": 526, + "Enchantment of Metaphysics": 527, + "Enchantment of Savagery": 528, + "Enchantment of Shadows": 529, + "Archer Ring": 530, + "Divine Bowstring": 531, + "Top of the Last Guardian's Bow": 519, + "Bottom of the Last Guardian's Bow": 518, + "Bow of the Last Guardian": 517, + "Heart of the Seer": 532, + "Vestments of Havoc Boots": 516, + "Vestments of Havoc Robe Top": 515, + "Vestments of Havoc Robe Bottom": 514, + "Vestments of Havoc Hood": 513, + "Divine Moon Guard and Lantern override token": 1066, + "Greater Sunshine ability codex": 533, + "Greater Death's Swiftness ability codex": 534, + "Codex of lost knowledge": 535, + "Champions Hurricane Cosmetic Ability Scroll": 536, + "Azure Dragonbreath Cosmetic Ability Scroll": 537, + "Gnonme Child T-Shirt Token": 538, + "King Black Dragon T-Shirt Token": 539, + "Wise Old Man T-Shirt Token": 540, + "Platinum Torva Armour Token": 541, + "Platinum Virtus Armour Token": 542, + "One of the many title scroll": 543, + "Party Title Scroll": 544, + "Platinum Pernix Armour Token": 545, + "Abyssal Scourge": 546, + "Bohr Pet Token (Bohring)": 547, + "Inferno Shoulder Cape": 552, + "Ultramarine Shoulder Cape": 551, + "Stargazer Shoulder Cape": 550, + "Guilded Shoulder Cape": 549, + "Wilderness Shoulder Cape": 548, + "Emerald Gauntlets Token": 553, + "Ruby Gauntlets Token": 554, + "Diamond Gauntlets token": 555, + "Emerald title scroll": 556, + "Ruby Title Scroll": 557, + "Halo of Returning (FSW)": 559, + "Challenger Halo (RuneScape Fresh Start World)": 558, + "Girlfriend": 562, + "Inverted Attack Skillcape (120)": 581, + "Haunted whetstone": 1085, + "Inverted Pet (FSW)": 564, + "Inverted Fishing Skillcape (120)": 590, + "Inverted Farming Skillcape (120)": 607, + "Disabled": 560, + "Inverted Construction Skillcape (120)": 608, + "Inverted Ranged Skillcape (120)": 591, + "Taboo Pet token": 565, + "Witch's Broom staff token": 566, + "Witch's potion token": 567, + "Dark Facet of Grace": 568, + "Dark Facet of Luck": 569, + "Dark Facet of Passage": 570, + "Chaotic Swiftness cosmetic ability scroll": 571, + "Molten barricade cosmetic ability scroll": 572, + "Shock barricade cosmetic ability scroll": 573, + "Purple Halloween Mask": 574, + "Wraith Walk Override Token": 575, + "Spooky Ghost Mask token": 576, + "Boolap bag Mask token": 578, + "Spooky Hare mask token": 579, + "Stratus Cloud Token": 580, + "Inverted Thieving Skillcape (120)": 605, + "Inverted Cooking Skillcape (120)": 593, + "Inverted Prayer Skillcape (120)": 594, + "Inverted Crafting Skillcape (120)": 595, + "Inverted Firemaking Skillcape (120)": 596, + "Inverted Magic Skillcape (120)": 597, + "Inverted Fletching Skillcape (120)": 602, + "Eclipsed Soul prayer codex": 1065, + "Baby Osseous pet Halloween appearance token": 1067, + "Inverted Woodcutting Skillcape (120)": 599, + "Inverted Constitution Skillcape (120)": 582, + "Inverted Mining Skillcape (120)": 583, + "Inverted Strength Skillcape (120)": 584, + "Inverted Agility Skillcape (120)": 585, + "Inverted Smithing Skillcape (120)": 586, + "Inverted Runecrafting Skillcape (120)": 600, + "Inverted Defence Skillcape (120)": 588, + "Inverted Dungeoneering Skillcape (120)": 601, + "Inverted Hunter Skillcape (120)": 609, + "Inverted Slayer Skillcape (120)": 606, + "Solly pet halloween appearance token": 1068, + "Inverted Summoning Skillcape (120)": 610, + "Mallory pet halloween appearance token": 1069, + "Mask of the Matriarchs": 1070, + "Inverted Archaeology Skillcape (120)": 613, + "Inverted Divination Skillcape (120)": 611, + "Inverted Invention Skillcape (120)": 612, + "Frosty Shoulder Cape": 614, + "Frozen Shoulder Cape": 615, + "Terry Pet Token": 616, + "Amascut chapel token": 1073, + "Frozen Touch of Death cosmetic ability scroll": 1076, + "Santa Costume Gloves": 624, + "Santa Costume Legs": 622, + "Santa Costume Top": 621, + "Santa Costume Boots": 623, + "Aurora Dye": 619, + "Inverted Quest Cape": 625, + "Wand of the Cywir": 627, + "Inverted Ramsay Pet Token": 630, + "Inverted Gemi Pet Token": 631, + "Inverted Baby Yagas House Halo Pet Token": 629, + "Inverted Morty Halo Pet Token": 628, + "Inverted Wallace Halo Pet Token": 632, + "Virtus mask": 666, + "Virtus robe top": 667, + "Virtus robe legs": 668, + "Merciless kiteshield": 669, + "Torva full helm": 670, + "Torva platebody": 671, + "Torva platelegs": 672, + "Torva gloves": 673, + "Torva boots": 674, + "Wyrm spike": 675, + "Wyrm heart": 676, + "Wyrm scalp": 677, + "Wyvern crossbow": 678, + "Intricate smoke-shrouded chest": 679, + "Intricate shadow chest": 680, + "Intricate blood stained chest": 681, + "Intricate ice chest": 682, + "Second age full helm": 683, + "Elite sirenic mask": 684, + "Elite sirenic hauberk": 685, + "Elite sirenic chaps": 686, + "Elite tectonic mask": 687, + "Elite tectonic robe top": 688, + "Elite tectonic robe bottom": 689, + "Chaotic berserk cosmetic ability scroll": 702, + "Chaotic hurricane cosmetic ability scroll": 703, + "Azure sunshine cosmetic ability scroll": 704, + "Inverted Willow Halo Pet Token": 633, + "Inverted Gordie Halo Pet Token": 634, + "Inverted Brains Halo Pet Token": 635, + "Inverted Bernie Halo Pet Token": 636, + "Inverted Bubbles Halo Pet Token": 637, + "Inverted Herbert Halo Pet Token": 638, + "Inverted Ace Halo Pet Token": 639, + "Inverted Malcolm Halo Pet Token": 640, + "Inverted Rocky Halo Pet Token": 641, + "Inverted Ghostly Halo Pet Token": 642, + "Inverted Sparky Halo Pet Token": 643, + "Inverted Rue Halo Pet Token": 644, + "Inverted Crabbe Halo Pet Token": 645, + "Inverted Shamini Halo Pet Token": 646, + "Inverted Smithy Halo Pet Token": 647, + "Inverted Kangali Halo Pet Token": 648, + "Inverted Ralph Halo Pet Token": 649, + "Inverted Woody Halo Pet Token": 650, + "Inverted Newton Halo Pet Token": 651, + "Inverted Flo Halo Pet Token": 250, + "Orb of the Cywir elders": 652, + "Wand of the Cywir elders": 653, + "Merethiels stave": 699, + "Inverted Archie Pet Token": 448, + "Inverted Dojo Mojo Pet": 308, + "Infinity hat": 654, + "Infinity top": 655, + "Infinity gloves": 656, + "Infinity bottoms": 657, + "infinity boots": 658, + "Passage of the abyss": 659, + "Grace of the elves": 660, + "Spider leg": 661, + "Reaper Necklace": 662, + "Hydrix": 663, + "Infinity Robes Set": 664, + "Decimation": 665, + "Dormant Zaros Godsword": 700, + "Dormant Staff of Sliske": 701, + "Inverted Sifu Pet Token": 577, + "Pernix cowl": 705, + "Pernix body": 706, + "Pernix chaps": 707, + "Pernix gloves": 708, + "Pernix boots": 709, + "Mask of the Grove Guardian": 1071, + "Inverted Herblore Skillcape (120)": 604, + "Pirate hook (left)": 711, + "Pirate hook (right)": 712, + "Double pirate hooks": 713, + "Heart of the Warrior": 714, + "Heart of the Archer": 715, + "Rose tinted glasses": 716, + "Rose Petal Aura Token": 717, + "Warrior ring": 718, + "Seers' ring": 719, + "Amulet of fury": 720, + "Essence of finality ornament kit": 721, + "Reaper ornament kit": 722, + "Grasping rune pouch": 723, + "Tracking gloves": 724, + "Static gloves": 725, + "Double escape codex": 726, + "Pneumatic gloves": 727, + "Dragon mattock": 728, + "Dragon pickaxe": 729, + "Vengeful kiteshield": 730, + "Gloves of passage": 731, + "Jaws of the abyss": 732, + "Flarefrost boots": 733, + "Hailfire boots": 734, + "Emberkeen boots": 735, + "Virtus gloves": 736, + "Virtus boots": 737, + "Virtus wand": 738, + "Virtus book": 739, + "Shadow glaive": 740, + "Off-hand shadow glaive": 741, + "Lucky dragonkin coin": 742, + "Celestial handwraps": 743, + "Ascension grips": 744, + "Ragefire boots": 745, + "Steadfast boots": 746, + "Glaiven boots": 747, + "Annihilation": 748, + "Obliteration": 749, + "Undead slayer ability codex": 750, + "Dragon Slayer ability codex": 751, + "Mining and Smithing Flyer": 752, + "Steel Gauntlets (non-ge)": 753, + "Camel staff": 754, + "Pitch can (full)": 755, + "Demonic Title Scroll (General)": 756, + "Demoic Title SCroll (Terrifying)": 757, + "Demoic Title Scroll (deacon)": 758, + "Demonic Title Scroll (Blazing)": 759, + "Royal Shoulder Cape (Red)": 760, + "Royal Shoulder cape (Black)": 761, + "Dragon crested shoulder cape": 762, + "Noble shoulder cape": 763, + "Pumpkin Souls cosmetic ability scroll": 1072, + "Gud Raider Axe": 765, + "Soul ornament kit": 766, + "Heralds Hat Token": 767, + "Heralds Jacket and Gloves Token": 768, + "Heralds Trousers and Boots Token": 769, + "Heralds Gloves and Orb Token": 770, + "Second Age Mage Mask": 771, + "Ruby Suit token": 772, + "Emerald Suit token": 773, + "Diamond Suit token": 774, + "Vis wax": 775, + "Zigzag Easter egg": 776, + "Striped Easter egg": 777, + "Spotted Easter egg": 778, + "Spiky Easter egg": 779, + "Smooth Easter egg": 780, + "Intricate Easter egg": 781, + "Captain Deathbeard's Hook token": 812, + "Captain Deathbeard's Hat token": 813, + "Captain Deathbeard's Feet token": 814, + "Captain Deathbeard's Doublet token": 815, + "Captain Deathbeard's Breeches token": 816, + "Captain Deathbeard's (phantom) Outfit token": 817, + "Pirate sheep pet token": 818, + "Walk the Plank emote token": 819, + "Scurvy the cannon pet token": 820, + "Cursed amascut sand": 822, + "Amulet of the forsaken": 826, + "Dragon hatchet": 827, + "Fletching cleaner (inactive)": 828, + "Slayer Wildcard": 830, + "Artisanal gears": 832, + "Blood Ice Barricade cosmetic ability": 833, + "Golden cape": 831, + "Azure Reprisal cosmetic ability scroll": 834, + "Woody Bunny appearance token": 811, + "Willow Bunny appearance token": 810, + "Wallace Bunny appearance token": 809, + "Mizyuyari": 836, + "Soul witch token": 838, + "Primal Guardian (Phantom Guardian) cosmetic ability scroll": 1074, + "Mask of the Araxytes": 1086, + "Dragonfire shroud": 842, + "Omni guard": 843, + "Soulbound Lantern": 844, + "Crown of the First necromancer": 845, + "Food wraps of the First necromancer": 846, + "Hand wrap of the First Necromancer": 847, + "Robe bottom of the First Necromancer": 848, + "Robe top of the First Necromancer": 849, + "Greater ritual candle": 850, + "Powerful ghostly ink": 851, + "Greater flaming skull": 852, + "Running Scared Walk Override Token": 853, + "Boulder Pet token": 854, + "Hood of subjugation": 855, + "Garb of subjugation": 856, + "Gloves of subjugation": 857, + "Gown of subjugation": 858, + "Boots of subjugation": 859, + "Fungal Tendrils cosmetic ability scroll": 861, + "Fungal Assault cosmetic ability scroll": 862, + "Fungal Hurricane cosmetic ability scroll": 863, + "Enforcer walk override token": 865, + "Hedge Teleport token": 866, + "Ensouled pumpkin mask": 872, + "O lantern title scroll": 873, + "Soul Surge cosmetic ability scroll": 874, + "Soul dive cosmetic ability scroll": 875, + "Icthlarin chape token": 876, + "Pumpkin trees token": 877, + "Pumpkin beret override token": 878, + "Vorkath Necromancy weapon override token": 882, + "Elite Dracolich coif": 883, + "Elite Dracolich boots": 884, + "Elite Dracolich chaps": 885, + "Elite Dracolich hauberk": 886, + "Elite Dracolich vambraces": 887, + "Hexer Braids hairstyle token": 889, + "Invoke Lord of Bones incantation codex": 890, + "Purple Santa hat": 891, + "Magical Bunny egg": 892, + "Magical Lamb egg": 893, + "Magical Chick egg": 894, + "Festive Warrior (Skeleton Warrior) scroll": 896, + "Fairy Light Fishing token": 895, + "Winter Hat (Aurora)": 899, + "Winter Scarf (Aurora)": 900, + "Cherry blossom fan token": 902, + "Cherry blossom wand token": 903, + "Cherry blossom orb token": 904, + "emerald cane": 905, + "ruby cane": 906, + "Third Age Druidic Staff": 490, + "Jagex": 907, + "Frozen Basic Attack (Necromancy) cosmetic ability scroll": 1075, + "Soul Dye": 837, + "Orange Halloween Mask": 871, + "Black Partyhat": 880, + "Frozen Finger of Death cosmetic ability scroll": 1077, + "Crystal Keys": 1021, + "Fat Snail": 1022, + "Dolorous Witch hairstyle token": 1023, + "Zamorakian title scroll (The Witch)": 1024, + "Zamorakian title scroll (Acolyte)": 1025, + "Zamorakian title scroll (Hierophant)": 1026, + "Zamorakian title scroll (High Priest/Priestess)": 1027, + "Chaotic Assault cosmetic ability scroll": 1028, + "Fungal Swiftness cosmetic ability scroll": 1029, + "Azure Hurricane cosmetic ability scroll": 1030, + "Heart of the Berserker": 1031, + "Rainbow Dragonbreath cosmetic ability scroll": 1032, + "Omen Bunny appearance token": 1033, + "Power Flower Basket": 1034, + "Emerald cape": 1035, + "Ruby cape": 1036, + "Diamond cape": 1037, + "Shadow Gem Pernix Token": 1038, + "Gnome Goggles": 1039, + "Master Wand": 1040, + "Jail cell key": 1041, + "Occultist's ring": 1042, + "Corrupted Combust cosmetic ability scroll": 1043, + "Balarak's sash brush": 1044, + "Skeka's hypnowand": 1045, + "Rainbow trail aura override token": 1046, + "Casual Beachwear outfit token": 1047, + "Summer Warrior (Skeleton Warrior token)": 1048, + "Arcane apprentice umbrella token": 1049, + "Demonic Title Scroll (Deceiver)": 1050, + "Shard of Genesis Essence": 1053, + "Divine Rage prayer codex": 1054, + "Scripture of Amascut": 1055, + "Manuscript of Amascut": 1056, + "Frozen Death Skulls cosmetic ability scroll": 1078, + "Frozen Living Death cosmetic ability scroll": 1079, + "Warped Basic Attack (Necromancy) cosmetic ability scroll": 1080, + "Warped Touch of Death cosmetic ability scroll": 1081, + "Warped Finger of Death cosmetic ability scroll": 1082, + "Warped Death Skulls cosmetic ability scroll": 1083, + "Warped Living Death cosmetic ability scroll": 1084, + "Spectral lens": 1087, + "Pestilent Torva Armour Token": 1088, + "Shrouded Veil token": 1121, + "Faded Veil token": 1122, + "Pink Candy Cane Token": 1186, + "Orange Candy Cane Token": 1187, + "Cyan Candy Cane Token": 1188, + "Blue Candy Cane Token": 1189, + "Red Candy Cane Token": 1190, + "Green Candy Cane Token": 1191, + "Purple Candy Cane Token": 1192, + "Black Candy Cane Token": 1193, + "Festive Guardian cosmetic ability scroll": 1194, + "Festive Warrior (Set 2) scroll": 1195, + "Masterwork bow": 1219, + "Primal hatchet": 1220, + "Winter Sports Outfit token": 1222, + "A mis-fortune from The Mighty Zoltan 1-17 (set)": 1252, + "Black Christmas scythe": 1120, + "Pink Santa hat": 1153, + "Aurora Trail aura override token": 1221, + "Snowball Pet Token": 1286, + "Aurora Santa hat": 1285, + "Roar of Awakening": 1051, + "Ode to Deceit": 1052, + "Scripture of Elidinis": 1062, + "Ranger Roll Walk override token": 825, + "Azure Berserk cosmetic ability scroll": 835, + "Ice barricade cosmetic ability scroll": 824, + "Azure Swiftness cosmetic ability scroll": 823, + "Greater Sonic wave ability codex": 821, + "Sparky Bunny appearance token": 808, + "Smithy Bunny appearance token": 807, + "Sifu Bunny appearance token": 806, + "Shamini Bunny appearance token": 805, + "Rue Bunny appearance token": 804, + "Rocky Bunny appearance token": 803, + "Ramsay Bunny appearance token": 802, + "Ralph Bunny appearance token": 801, + "Newton Bunny appearance token": 800, + "Morty Bunny appearance token": 799, + "Malcolm Bunny appearance token": 798, + "Kangali Bunny appearance token": 797, + "Herbert Bunny appearance token": 796, + "Gordie Bunny appearance token": 795, + "Ghostly Bunny appearance token": 794, + "Gemi Bunny appearance token": 793, + "Flo Bunny appearance token": 792, + "Dojo Mojo Bunny appearance token": 791, + "Crabbe Bunny appearance token": 790, + "Bubbles Bunny appearance token": 789, + "Brains Bunny appearance token": 788, + "Bernie Bunny appearance token": 787, + "Baby yaga's House Bunny appearance token": 786, + "Archie Bunny appearance token": 785, + "Ace Bunny appearance token": 784, + "Full Easter basket": 783, + "Empty Easter basket": 782, + "Frozen Surge cosmetic ability scroll": 1318, + "Frozen Escape cosmetic ability scroll": 1319, + "Frozen Dive cosmetic ability scroll": 1320, + "Frozen Overpower cosmetic ability scroll": 1321, + "Frozen Deadshot cosmetic ability scroll": 1322, + "Frozen Omnipower cosmetic ability scroll": 1323, + "Warped Surge cosmetic ability scroll": 1324, + "Warped Escape cosmetic ability scroll": 1325, + "Warped Dive cosmetic ability scroll": 1326, + "Warped Overpower cosmetic ability scroll": 1327, + "Warped Deadshot cosmetic ability scroll": 1328, + "Warped Omnipower cosmetic ability scroll": 1329, + "Masterwork Staff": 1351, + "Vorkath's scale": 1352, + "Hellforged Warrior Armour Token": 1384, + "Dragonstone Circlet token": 1385, + "Onyx Circlet token": 1386, + "Hydrix Circlet token": 1387, + "Dragonstone title scroll": 1388, + "Onyx title scroll": 1389, + "Hydrix title scroll": 1390, + "Solid Gold Easter egg": 1391, + "Flower Basket Token": 1392, + "Chocolate Basket Token": 1393, + "Daisy Basket Token": 1394, + "Blue Flower Basket Token": 1395, + "Springbloom Hat token": 1417, + "Springbloom Staff token": 1418, + "Witch's Ride walk token": 1419, + "Springbloom Hime hairstyle token": 1420, + "Springbloom Aura token": 1421, + "Masterwork magic boots": 1450, + "Masterwork magic gloves": 1451, + "Masterwork magic hat": 1452, + "Masterwork magic robe bottom": 1453, + "Masterwork magic robe top": 1454, + "Dragonstone Gala Attire token": 1483, + "Onyx Gala Attire token": 1484, + "Hydrix Gala Attire token": 1485, + "Duskrunner's Hairstyle token": 1516, + "Duskrunner's Outfit token": 1517, + "Tumeken's Light": 1549, + "Devourer's Guard": 1550, + "Mask of Tumeken's resplendence": 1551, + "Robe top of Tumeken's resplendence": 1552, + "Boots of Tumeken's resplendence": 1553, + "Gloves of Tumeken's resplendence": 1554, + "Robe bottom of Tumeken's resplendence": 1555, + "The Devourer's Nexus (unattuned)": 1556, + "Tuska's Wrath ability codex": 1582, + "Heavenforged Warrior Armour Token": 1615, + "Chaotic crossbow frozen dye kit": 1616, + "Chaotic crossbow warped dye kit": 1617, + "Chaotic maul frozen dye kit": 1618, + "Chaotic maul warped dye kit": 1619, + "Chaotic rapier frozen dye kit": 1620, + "Chaotic rapier warped dye kit": 1621, + "Warped Kinship Teleport token": 1622, + "Warped Loot Beam token": 1623, + "Warped Trail token": 1624, + "Frozen Kinship Teleport token": 1625, + "Frozen Loot Beam token": 1626, + "Frozen Trail token": 1627, + "Shadowstep aura override token": 1628, + "Smokestep aura override token": 1629, + "Black pumpkin": 1630, + "Red pumpkin": 1631, + "Purple pumpkin": 1632, + "Black Ensouled pumpkin mask": 1633, + "Red Ensouled pumpkin mask": 1634, + "Bloodthirsty walk override token": 1635, + "Soul Escape cosmetic ability scroll": 1636, + "Blood soul witch token": 1637, + "lucille token": 1638, + "Witch's Outfit token": 1639, + "Batnado Teleport token": 1640, + "Yellow Hallowe'en mask": 1641, + "Soul dyed halloween mask": 1642, + "Blood Soul Surge cosmetic ability scroll": 1643, + "Blood Soul Dive cosmetic ability scroll": 1644, + "Blood Soul Escape cosmetic ability scroll": 1645, + "Catalyst Bloat cosmetic ability scroll": 1648, + "Catalyst Detonate cosmetic ability scroll": 1649, + "Catalyst Flurry cosmetic ability scroll": 1650, + "Catalyst Harpoon token": 1651, + "Catalyst Hatchet token": 1652, + "Catalyst Pickaxe token": 1653, + "Catalyst Reflect cosmetic ability scroll": 1654, + "Catalyst Relic hunter (tier 1) token": 1655, + "Catalyst Relic hunter (tier 2) token": 1656, + "Catalyst Relic hunter (tier 3) token": 1657, + "Catalyst Snap Shot cosmetic ability scroll": 1658, + "Catalyst aura token": 1659, + "Catalyst meditate rest token": 1660, + "Catalyst teleport token": 1661, + "Hexi pet token": 1662, + "Gloomfire bow": 1663, + "Legatus's Emberstaff": 1664, + "Misalionar's Death Mask": 1665, + "Varanus's Mercy": 1666, + "Black Giftwrapped Bow token": 1667, + "Black Giftwrapped Guard token": 1668, + "Black Giftwrapped Longsword token": 1669, + "Black Giftwrapped Staff token": 1670, + "Yellow Santa hat": 1671, + "Blue Santa hat": 1672, + "Moonlight Enchanter Robes token": 1673, + "Eclipse Enchanter Robes token": 1674, + "Deck Caster Woodcutting token": 1675, + "Cape of Devotion token": 1676, + "Cape of Devastation token": 1677, + "Symbol of Devotion token": 1678, + "Symbol of Devastation token": 1679, + "Blessed Wild Magic scroll": 1680, + "Corrupted Wild Magic scroll": 1681, + "Blessed Chain scroll": 1682, + "Corrupted Chain scroll": 1683, + "Blessed Concentrated Blast scroll": 1684, + "Corrupted Concentrated Blast scroll": 1685, + "Primal 2h Sword (Red) Token": 1686, + "Primal Pickaxe (Red) Token": 1687, + "Warped Daemonheim Armour Token": 1688, + "Dolorous Witch Outfit token": 1689, + "Tumeken Translocate token": 1690, + "Amascut Translocate token": 1691, + "Phoenix Knight Armour token": 1692, + "Dark Phoenix Knight Armour token": 1693, + "Visage of the First Necromancer": 1694, + "Am-hej": 1695, + "Jal-tok-yt": 1696, + "Ring of Vitur": 1697, + "Glacial Phoenix": 1698, + "Deadly Highwayman's Outfit (Master) token": 1699, + "Herald of Amascut Armour token": 1700, + "Herald of Tumeken Armour token": 1701, + "Black yo-yo": 1702, + "Yulemourne Armour Override Token": 1714, + "Yulemourne Greatsword Override Token": 1715, + "Frosted Tips hairstyle token": 1716, + "Dragon Harpoon": 1717, + "Stalker's charm": 1718, + "Nodon spike harness": 1719 +} \ No newline at end of file diff --git a/chrome-extension/options.html b/chrome-extension/options.html new file mode 100644 index 0000000..060f35e --- /dev/null +++ b/chrome-extension/options.html @@ -0,0 +1,69 @@ + + + + + Ely Wiki Extension Options + + + + + + + + +
+ +
+ Leave empty to use the bundled extension data.
+ Should link to the raw json file of items. +
+ + + + + diff --git a/chrome-extension/options.js b/chrome-extension/options.js new file mode 100644 index 0000000..1c3c96c --- /dev/null +++ b/chrome-extension/options.js @@ -0,0 +1,19 @@ +document.getElementById('save').addEventListener('click', () => { + const dataUrl = document.getElementById('dataUrl').value.trim(); + + chrome.storage.sync.set({ customDataUrl: dataUrl }, () => { + const status = document.getElementById('status'); + status.textContent = 'Options saved.'; + setTimeout(() => { + status.textContent = ''; + }, 2000); + }); +}); + +document.addEventListener('DOMContentLoaded', () => { + chrome.storage.sync.get(['customDataUrl'], (items) => { + if (items.customDataUrl) { + document.getElementById('dataUrl').value = items.customDataUrl; + } + }); +}); diff --git a/download_data.py b/download_data.py new file mode 100644 index 0000000..688bdb1 --- /dev/null +++ b/download_data.py @@ -0,0 +1,61 @@ +import requests +import re +import json +import ast +from bs4 import BeautifulSoup + +def extract_data_from_page(url): + response = requests.get(url) + response.raise_for_status() + with open("response.html", "w", encoding="utf-8") as f: + f.write(response.text) + soup = BeautifulSoup(response.text, 'html.parser') + script_tags = soup.find_all('script') + + for script in script_tags: + if script.string: + lines = script.string.split('\n') + for line in lines: + if re.match(r'^\s*data\s*=', line): + match = re.search(r'data\s*=\s*(.+)', line) + if match: + data_str = match.group(1).rstrip(';').strip() + try: + data = ast.literal_eval(data_str) + return data + except (ValueError, SyntaxError): + continue + raise ValueError("Data object not found in script tags") + +if __name__ == "__main__": + url = "https://ely.gg" + data = extract_data_from_page(url) + new_data = {} + + replacement_map = { + 'greater chain codex': 'Greater Chain ability codex', + 'Fractured Armadyl Symbol (Kerapac)': 'Fractured Armadyl Symbol', + 'Fractured Stabilization Gem (Kerapac)': 'Fractured Stabilisation Gem', + 'Loved Up Walk Override': 'Loved Up Walk Override Token', + 'Mizyuyari': 'Mizuyari', + 'O lantern title scroll': "'o'-lantern' title scroll", + 'OG Gem Cape Token': 'Gem cape token', + 'Robin': 'Robin (item)', + 'Red Santa Hat': 'Santa Hat', + "One of the many title scroll": "'O ne of the many' title scroll", + "Party Title Scroll": "'Party' title scroll", + } + + for item in data: + if 'inverted' in item['value'].lower(): + item['value'] = item['value'].replace('(120)', 'token') + + for original_key, replacement_value in replacement_map.items(): + if item['value'].lower() == original_key.lower(): + item['value'] = replacement_value + break + + new_data[item['value'].strip()] = item['id'] + + with open('chrome-extension/new_data.json', 'w') as f: + json.dump(new_data, f, indent=4) diff --git a/new_data.json b/new_data.json new file mode 100644 index 0000000..56c1e26 --- /dev/null +++ b/new_data.json @@ -0,0 +1,1090 @@ +{ + "White Partyhat": 1, + "Yellow Partyhat": 2, + "Purple Partyhat": 3, + "Red Partyhat": 4, + "Christmas Scythe": 5, + "Loved Up Walk Override": 6, + "Assassin Walk Override Token": 9, + "Party fever Walk Override Token": 10, + "Conga Dance Override Token": 11, + "Treasure Dive Teleport Token": 12, + "Sand Dive Teleport Token": 13, + "Mining Away Teleport Token": 14, + "Rainbow Teleport Token": 15, + "Stocking Teleport Token": 17, + "Bucking Yak Teleport Token": 18, + "Christmas Lootbeam Token": 19, + "Summer Prize Token": 20, + "Buddy Pet Token": 22, + "Zoltan Pet Token": 23, + "Seahorse Follower Pet Token": 24, + "Starfish Follower Pet Token": 25, + "Pufferfish Follower Pet Token": 26, + "Banana Boat Mount Token": 27, + "Dizzy Stick Token": 28, + "Fish in a Bag Token": 29, + "Zoltan Plushie Token": 30, + "Stack of Presents Token": 31, + "Penguin Plush Token": 32, + "Mammoth Plush Token": 33, + "Lederhosen Terrorbird Mount Token": 35, + "Bubble Blower Token": 36, + "Yak Plushie Token": 37, + "Yak Balloon Token": 38, + "Luchador Mask Token": 39, + "Novtumberfest Dance Emotes Token": 42, + "Test of Strength Emote token": 43, + "Zarosian Apron Token": 46, + "Vegetable Apron Token": 47, + "Beach Apron Token": 48, + "Crustacea Armour Token": 49, + "Meditation Rest Animation Token": 52, + "Hacky Sack Resting Emote Token": 53, + "Sand Dunk Resting Emote Token": 54, + "Contact Juggling Resting Token": 55, + "Palm Tree Rest Emote Token": 56, + "Carrying Steins Resting Token": 57, + "Sandy Sandwich Rest Override Token": 58, + "Cocktail Flare Rest Override Token": 59, + "Snowman Building Rest Token": 60, + "Shade Thrower Rest Token": 61, + "Novtumberfest Outfit Token": 62, + "Elf Shoes Token": 63, + "Dancer Outfit Token": 64, + "Crown of Seasons": 65, + "Cloak of Seasons": 66, + "Chest of Seasons": 67, + "Glove of Seasons": 69, + "Boots of Seasons": 70, + "Pet of Seasons": 71, + "Santa Claws Token": 72, + "Glacial Shieldbow Token": 73, + "Dizzy Teleport Token": 16, + "Santa Paws Token": 76, + "Snow Parasol": 77, + "Snow Cape": 78, + "Black Santa Hat": 79, + "Christmas Cracker": 84, + "Easter Egg": 85, + "Pumpkin": 86, + "Disk of Returning": 87, + "Half Jug Wine": 88, + "Green Partyhat": 89, + "Blue Partyhat": 90, + "Rainbow Wand": 92, + "Selfie Emote Token": 41, + "Red Santa Hat": 80, + "Zombie Walk Override Token": 50, + "OG Gem Cape Token": 51, + "Red Halloween Mask": 83, + "Blue Halloween Mask": 82, + "Green Halloween Mask": 81, + "Crab Hat": 91, + "Party Hat Jumper": 75, + "Bottom of Seasons": 68, + "Snowverload Plush Token": 34, + "Rainbow Scythe": 93, + "Rainbow Pet Token": 94, + "Infernal Cerberus faulds token": 312, + "Plague Walk Override Token": 7, + "Rainbow Parasol": 95, + "Rainbow Gaze": 96, + "Clover Parasol": 97, + "Surfboard Shield Token": 98, + "Ink Shooter Token": 99, + "Tribal Pet Token": 100, + "Snowman Pet Token": 101, + "Christmas Tree Hat": 102, + "Fish Mask": 103, + "Shadow Gem Sack Token": 104, + "Shadow Gem Cape Token": 105, + "Shadow Gem Necklace Token": 106, + "Shadow Gem Crown Token": 107, + "Hot Sand Walk Override Token": 8, + "Bone Master Outfit Token": 112, + "Earhart the penguin token": 114, + "Rainbow Cape": 115, + "Tomb Gorilla Pet Token": 116, + "Arthur Pet Token": 117, + "Skeletal Bear Pet Token": 118, + "Clawdia Claws Token": 119, + "Keg Pet Token": 122, + "Christmas Tree Cape": 123, + "Present Sack Token": 124, + "Present Hammer Token": 125, + "Holly Wreath": 126, + "OG Gem Crown Token": 108, + "Rainbow Amulet": 127, + "Duck Ring Token": 120, + "Goebie Backpack Token": 128, + "Sandcastle Pet Token": 129, + "Octopus Pet Token": 130, + "Carrot Lance Token": 131, + "Cottontail Legs Token": 132, + "Cottontail Top token": 133, + "Cottontail Helmet Token": 134, + "Forsaken Graahk Pet Token": 135, + "Crypt Scythe Token": 136, + "Crypt Staff Token": 137, + "Crypt Shieldbow Token": 138, + "Hook a Duck Flail Token": 139, + "Venturer Outfit Token": 140, + "Menowin Outfit Token": 141, + "Mallet Token": 151, + "Crystal Ball Token": 152, + "Pickaxe Hat Token": 153, + "Face Paint Token": 154, + "Easter Egg Hat Token": 142, + "Robin": 143, + "Woolly Pudding Hat": 144, + "Starfish Balloon": 145, + "Pufferfish Balloon": 146, + "Seahorse Balloon": 147, + "Beach Armour Token": 148, + "Pufferfish Launcher Token": 149, + "Crusty Pet Token": 150, + "Sandy Maul Override Token": 155, + "Sandy 2h Sword Token": 156, + "Sandy Club Token": 157, + "Mint Hair Head Token": 158, + "Strawberry Hair Head Token": 159, + "Vanilla Hair Head Token": 160, + "Conga Eel Whip Token": 161, + "Ice Lolly Wand Token": 162, + "Shark Fin Token": 163, + "Lifeguard Chair Head Token": 164, + "Kauai Parasol Token": 165, + "Oahu Parasol Token": 166, + "Kahului Parasol Token": 167, + "Maui Parasol Token": 168, + "Hawaii Parasol Token": 169, + "Pyramid Hat Head Token": 170, + "Coral Sword Token": 171, + "Coral Dagger Token": 172, + "Phoebe Pet Token": 173, + "Gillbert Pet Token": 174, + "Snorkel Token": 175, + "Throwing Starfish Token": 176, + "Clawdia Hat Token": 177, + "Dragon Ring Token": 178, + "Stick Of Rock Token": 179, + "Rubber Turkey": 180, + "Off-hand Rubber Turkey": 181, + "Clawdia Wings Token": 182, + "Ocean Archer's Helm": 183, + "Ocean's Archer Body": 184, + "Ocean's Archer Legs": 185, + "Ocean's Archer Bow": 186, + "OG Gem Necklace Token": 110, + "OG Gem Sack Token": 109, + "Wolpertinger Pet Token": 121, + "Ocean's Archer Crossbow": 187, + "Cerberus Pet Token": 188, + "Cerberus Boots Token": 189, + "Shadowy Egg": 313, + "Cerberus Breastplate Token": 190, + "Cerberus Faulds Token": 191, + "Cerberus Gloves Token": 192, + "Cerberus Helmet Token": 193, + "Meowsketeer's Hat Token": 194, + "Meowsketeer's Tunic Token": 195, + "Meowsketeer's Trousers Token": 196, + "Meowsketeer's Gloves Token": 197, + "Meowsketeer's Boots Token": 198, + "Meowsketeer's Scarf Token": 199, + "Meowsketeer's Rapier Token": 200, + "Sameowrai's Helmet Token": 201, + "Sameowrai's Breastplate Token": 202, + "Sameowrai's Faulds Token": 203, + "Sameowrai's Gauntlets Token": 204, + "Sameowrai's Tabi Token": 205, + "Sameowrai's Bow Token": 206, + "Sameowrai's Cata-Nya Token": 207, + "Blue Shorthair Fur Token": 208, + "Phoenix Aura Token": 210, + "Phoenix Wing Backpack Token": 211, + "Christmas Tree Jumper": 74, + "Present head token": 214, + "Terrorbird Plushie": 212, + "Christmas Tree Kite": 213, + "Phoenix Mimic Pet Token": 215, + "Shadow Gem Helmet": 216, + "Christmas Penguin Jumper": 217, + "Wreath Shield Token": 218, + "Rainbow Bow Token": 219, + "Rainbow Aura": 263, + "Treasure Resting Token": 220, + "Beer Goggles Token": 225, + "Gingerbread Necklace Token": 224, + "Stein Weapon Token": 226, + "Shark bait token": 227, + "Fortune Cape Token": 228, + "Wreath Crown Token": 229, + "Water Balloon Launcher": 230, + "Bucky Token": 231, + "Clover Wand Token": 232, + "Clover Staff Token": 234, + "Christmas Pudding Balloon": 235, + "Squeaker Axe Token": 236, + "Bloodtusk Warlord Helmet": 237, + "Bloodtusk Warlord Upper Body": 238, + "Bloodtusk Warlord Lower Body": 239, + "Cadavaberry Parasol": 241, + "Coconut parasol": 242, + "Dwellberry parasol": 243, + "Lime parasol": 245, + "Orange parasol": 246, + "Strawberry parasol": 247, + "Watermelon parasol": 248, + "Apple Parasol": 240, + "Chinchompa Jumper Token": 222, + "Clover Bow Token": 233, + "Guthix Jumper Token": 223, + "Hypnotic parasol Token": 249, + "Lemon parasol": 244, + "Purified Swords": 274, + "Token Index": 265, + "Bond": 259, + "Blood Dye": 252, + "Caller of the Sea Token": 256, + "Fortune Teller Outfit Token": 257, + "Orlando Smith Hat": 258, + "Ice Dye": 255, + "Shadow Dye": 253, + "Rainbow Halo Token": 209, + "Loved Up Rest": 275, + "Shadow Gem Ranged": 260, + "Purified Crossbow": 272, + "Purified Shortbow": 267, + "Purified Wand and Orb": 269, + "Purified Greatsword": 270, + "Purified Staff": 268, + "Purified Halberd": 271, + "Rudolph Necklace Token": 279, + "Purified 2h Crossbow": 266, + "Cerberus Staff Token": 276, + "Cerberus Claw Token": 278, + "Rares Index": 264, + "Third Age Dye": 251, + "Barrows Dye": 254, + "Shadow Gem Melee": 261, + "Clover Axe Token": 273, + "Cerberus Bow Tokwn": 277, + "Shadow Gem Magic": 262, + "Pretzel Shield Token": 221, + "Barrel of Monkeys": 280, + "Beach Ball Token": 281, + "Bucket Head Token": 282, + "Bucket Staff Override Token": 284, + "Blunting Whip Token": 285, + "Tavias Fishing Rod": 297, + "Guildmaster Tony's mattock": 298, + "Hazelmere's Signet Ring": 299, + "Seashell Necklace Tokens": 335, + "Ammonite Necklace Token": 336, + "Rainbow WIngs Token": 318, + "Easter Pet Token (Eggos)": 21, + "Scripture of Jas": 338, + "Staff of Sliske": 321, + "Inquisitor Staff": 322, + "Wand of the Praesul (Praesul Wand)": 323, + "Surfboard Emote Token": 345, + "Throwing Disk Token": 346, + "Clover Sword Token": 286, + "Pot of Gold Token": 287, + "Rei Ti Ronin Bracers": 292, + "Cinderbane Gloves": 351, + "Stephanie Pet Token": 327, + "Beach Towel Outfit Token": 328, + "Essence of Finality": 352, + "Elegant Sun Hat Token": 332, + "Menaphos Beachwear Token": 333, + "Luck of the Dwarves": 354, + "Amulet of Souls": 355, + "Khopesh of Tumeken": 365, + "Greater Concentrated Blast Codex": 339, + "Kerapac Wrist Wraps": 340, + "Deathtouch Bracelet": 356, + "Manuscript of Bik": 342, + "Manuscript of Ful": 343, + "Manuscript of Wen": 344, + "Hexhunter Bow": 357, + "Terrasaur Maul": 358, + "Greater Fury Ability Codex": 359, + "Noxious Longbow": 303, + "Noxious Scythe": 304, + "Noxious Staff": 305, + "Blightbound Crossbow": 306, + "Zaros Godsword": 307, + "Seren Godbow": 309, + "Rei Ti Ronin Faulds": 289, + "Rei Ti Ronin Scarf": 290, + "Rei Ti Nonin Sugegasa": 291, + "Rei Ti Ronin Tunic": 293, + "Pinata Plushie": 294, + "Pinata Sombrero": 295, + "Leveller and Bucket token": 296, + "Buried in Sand Rest": 301, + "Tongue Cape": 302, + "Infernal Cerberus breastplate": 314, + "Infernal Cerberus gloves": 315, + "Infernal Cerberus boots": 316, + "Gnome Scarf": 317, + "Chocolate Hair Head Token": 320, + "Second Age Platebody": 325, + "Second Age Platelegs": 326, + "Eldritch Crossbow": 300, + "Beachball Orb Token": 40, + "Bronzed Sun Hat Token": 330, + "Elysian Spirit Shield": 360, + "Greater Chain Codex": 324, + "Divine Spirit Shield": 361, + "Staff of Armadyl": 337, + "Fractured Armadyl Symbol (Kerapac)": 349, + "Fractured Shaft (Kerapac)": 348, + "Bronzed Sandals Token": 329, + "Manuscript of Jas": 341, + "Magical Eggs": 319, + "Spectral Spirit Shield": 362, + "Menaphos Parasol Token": 334, + "Elegant Sandals Token": 331, + "Arcane Spirit Shield": 363, + "Off-Hand Blightbound Crossbow": 364, + "Masterwork Spear of Annhiliation": 367, + "Dragon Rider Lance": 368, + "Imperium Core": 369, + "Khopesh of Elidinis (Off-Hand Khopesh)": 366, + "Ascension Crossbow": 370, + "Off-Hand Ascension Crossbow": 371, + "Trimmed Mastework Helm": 372, + "Trimmed Masterwork Platebody": 373, + "Trimmed Masterwork Platelegs": 374, + "Fractured Stabilization Gem (Kerapac)": 347, + "Shovel Sword Token": 283, + "trout (test item)": 310, + "Trimmed Masterwork Gloves": 375, + "Trimmed Masterwork Boots": 376, + "Ring of Death": 353, + "Praesul Codex": 377, + "Berserker Ring": 378, + "Ingenuity of the Humans Ability Codex": 379, + "Mazcab Ability Codex": 381, + "Fleeting Boots": 382, + "Greater Flurry Ability Codex": 380, + "Seismic Singularity": 383, + "Seismic Wand": 384, + "Greater Barge Ability Codex": 385, + "Erethdors Grimoire": 386, + "Reprisal Ability Codex": 387, + "Brooch of the Gods": 388, + "Dormant Seren Godbow": 389, + "Divert Ability Codex": 390, + "Eldritch Crossbow Stock": 391, + "Eldritch Crossbow Limb": 392, + "Eldritch Crossbow Mechanism": 393, + "Statius Warhammer": 394, + "Kinetic Cyclone Upgrade Kit": 396, + "Oldak Coil Upgrade Kit": 397, + "Dwarf Multicannon Upgrade Kit": 395, + "Shadow Spike": 398, + "Laniakeas Spear": 399, + "Greater Ricochet Ability Codex": 350, + "Alchemical Hydrix": 400, + "Drygore Longsword": 401, + "Off-hand Drygore Longsword": 402, + "Drygore Rapier": 403, + "Off-Hand Drygore Rapier": 404, + "Torn Grimoire Page": 405, + "Alchemical Onyx": 406, + "Drygore Mace": 407, + "Off-hand Drygore Mace": 408, + "Double Surge Codex": 409, + "Scripture of Wen": 419, + "Nightmare Gauntlets": 418, + "Enchanted Nightmare Gauntlets": 416, + "Enhanced Kerapac's wrist wraps": 415, + "Enhanced Gloves of Passage": 414, + "Croesus Enriched Root": 436, + "Dark Shard of Leng (t95)": 412, + "Dark Ice Shard": 411, + "Infernal Cerberus Pet": 420, + "Dark Ice Sliver": 410, + "Dark Sliver of Leng (t95)": 413, + "Rainbow Outfit Token": 421, + "Primal Pickaxe +5": 1057, + "Cryptbloom Top (Croesus)": 424, + "Cryptbloom Bottoms (Croesus)": 425, + "Cryptbloom Gloves (Croesus)": 426, + "Cryptbloom Boots (Croesus)": 427, + "Croesus Foultorch": 433, + "Croesus Sporehammer": 434, + "Tagga's Corehammer": 437, + "Sana's Fyrtorch": 438, + "Cryptbloom Helm (Cryptbloom Armour)": 423, + "Scripture of Bik": 439, + "Third Age Druidic Cloak": 440, + "Scripture of Ful": 444, + "Obsidian Blade (TzKal-Zuk)": 445, + "Magma Core (TzekHaar Front)": 446, + "Ancient Hilt (TzekHaar Front)": 447, + "Pernix's Quiver": 450, + "Pernix Fragments": 449, + "Golden Partyhat": 451, + "Frosty Cerberus Claws Token": 455, + "Frosty Cerberus Boots Token": 452, + "Frosty Cerberus Bow Token": 453, + "Frosty Cerberus Breastplate Token": 454, + "Frosty Cerberus Faulds Token": 456, + "Frosty Cerberus Gloves Token": 457, + "Frosty Cerberus Helmet Token": 458, + "Frosty Cerberus Pet Token": 459, + "Frosty Cerberus Staff Token": 460, + "Green Santa Hat": 461, + "Frosted Wreath": 463, + "Croesus Spore Sack": 435, + "Magma Tempest Ability Codex": 442, + "Abomination Cape": 441, + "Ek-ZekKil (Zuk Sword)": 443, + "Masterwork 2h sword": 1058, + "Primal 2h sword": 1059, + "Runic attuner": 1060, + "Gift Wrap Scythe": 462, + "Rudolph Jumper": 464, + "Left Banana of Knowledge": 465, + "Right Banana of Knowledge": 466, + "Armadyl Battlestaff": 467, + "Fayre Dancer Emote Pack Two Token": 44, + "Fayre Dancer Emote Pack One Token": 45, + "Plague Rest Override Token": 508, + "Plague Teleport Override Token": 509, + "Flower Hairpin Token": 510, + "Oar Token": 511, + "Iaia Beachwear Outfit Token": 512, + "Golden Roses": 470, + "Fragment of Het": 468, + "Third Age Amulet": 476, + "Second Age Robe Top": 478, + "Second Age Robe Bottom": 479, + "Third Age Vambracers": 489, + "Second Age Range Coif": 491, + "memory dowser": 1061, + "Second Age Range Legs": 487, + "Second Age Range Top": 486, + "Third Age Mage Hat": 485, + "Third Age Coif": 484, + "Third Age Robe Top": 475, + "Third Age Full Helmet": 471, + "Third Age Kiteshield": 474, + "Third Age Platelegs": 473, + "Third Age Platebody": 472, + "Third Age Robe Legs": 477, + "Third Age Druidic Wreath": 488, + "Third Age Rage Top": 483, + "Third Age Range Legs": 482, + "Third Age Druidic Top": 480, + "Third Age Druidic Bottom": 481, + "Second Age Sword": 492, + "Second Age Bow": 493, + "Second Age Staff": 494, + "Rainbow Boquet Wand Token": 495, + "Sceptre of Enchantment": 496, + "Coin of Enchantment": 497, + "Oil of Enchantment": 498, + "Peep the Chick Pet Token": 502, + "Diamond Cane": 504, + "Rainbow Title Scroll": 506, + "Rainbow Glasses": 505, + "Woodland Fox Ears": 500, + "Diamond Title Scroll": 503, + "Woodland Fox Tail": 501, + "Hall of Fame Walk Token": 499, + "Demon Slayer Codex": 507, + "Latent Offering": 1063, + "Manuscript of Elidinis": 1064, + "Chaos Roar ability codex": 520, + "Enchantment of Affliction": 521, + "Enchantment of Agony": 522, + "Enchantment of Dispelling": 523, + "Enchantment of Dread": 524, + "Enchantment of Flames": 525, + "Enchantment of Heroism": 526, + "Enchantment of Metaphysics": 527, + "Enchantment of Savagery": 528, + "Enchantment of Shadows": 529, + "Archer Ring": 530, + "Divine Bowstring": 531, + "Top of the Last Guardian's Bow": 519, + "Bottom of the Last Guardian's Bow": 518, + "Bow of the Last Guardian": 517, + "Heart of the Seer": 532, + "Vestments of Havoc Boots": 516, + "Vestments of Havoc Robe Top": 515, + "Vestments of Havoc Robe Bottom": 514, + "Vestments of Havoc Hood": 513, + "Divine Moon Guard and Lantern override token": 1066, + "Greater Sunshine ability codex": 533, + "Greater Death's Swiftness ability codex": 534, + "Codex of lost knowledge": 535, + "Champions Hurricane Cosmetic Ability Scroll": 536, + "Azure Dragonbreath Cosmetic Ability Scroll": 537, + "Gnonme Child T-Shirt Token": 538, + "King Black Dragon T-Shirt Token": 539, + "Wise Old Man T-Shirt Token": 540, + "Platinum Torva Armour Token": 541, + "Platinum Virtus Armour Token": 542, + "One of the many title scroll": 543, + "Party Title Scroll": 544, + "Platinum Pernix Armour Token": 545, + "Abyssal Scourge": 546, + "Bohr Pet Token (Bohring)": 547, + "Inferno Shoulder Cape": 552, + "Ultramarine Shoulder Cape": 551, + "Stargazer Shoulder Cape": 550, + "Guilded Shoulder Cape": 549, + "Wilderness Shoulder Cape": 548, + "Emerald Gauntlets Token": 553, + "Ruby Gauntlets Token": 554, + "Diamond Gauntlets token": 555, + "Emerald title scroll": 556, + "Ruby Title Scroll": 557, + "Halo of Returning (FSW)": 559, + "Challenger Halo (RuneScape Fresh Start World)": 558, + "Girlfriend": 562, + "Inverted Attack Skillcape (120)": 581, + "Haunted whetstone": 1085, + "Inverted Pet (FSW)": 564, + "Inverted Fishing Skillcape (120)": 590, + "Inverted Farming Skillcape (120)": 607, + "Disabled": 560, + "Inverted Construction Skillcape (120)": 608, + "Inverted Ranged Skillcape (120)": 591, + "Taboo Pet token": 565, + "Witch's Broom staff token": 566, + "Witch's potion token": 567, + "Dark Facet of Grace": 568, + "Dark Facet of Luck": 569, + "Dark Facet of Passage": 570, + "Chaotic Swiftness cosmetic ability scroll": 571, + "Molten barricade cosmetic ability scroll": 572, + "Shock barricade cosmetic ability scroll": 573, + "Purple Halloween Mask": 574, + "Wraith Walk Override Token": 575, + "Spooky Ghost Mask token": 576, + "Boolap bag Mask token": 578, + "Spooky Hare mask token": 579, + "Stratus Cloud Token": 580, + "Inverted Thieving Skillcape (120)": 605, + "Inverted Cooking Skillcape (120)": 593, + "Inverted Prayer Skillcape (120)": 594, + "Inverted Crafting Skillcape (120)": 595, + "Inverted Firemaking Skillcape (120)": 596, + "Inverted Magic Skillcape (120)": 597, + "Inverted Fletching Skillcape (120)": 602, + "Eclipsed Soul prayer codex": 1065, + "Baby Osseous pet Halloween appearance token": 1067, + "Inverted Woodcutting Skillcape (120)": 599, + "Inverted Constitution Skillcape (120)": 582, + "Inverted Mining Skillcape (120)": 583, + "Inverted Strength Skillcape (120)": 584, + "Inverted Agility Skillcape (120)": 585, + "Inverted Smithing Skillcape (120)": 586, + "Inverted Runecrafting Skillcape (120)": 600, + "Inverted Defence Skillcape (120)": 588, + "Inverted Dungeoneering Skillcape (120)": 601, + "Inverted Hunter Skillcape (120)": 609, + "Inverted Slayer Skillcape (120)": 606, + "Solly pet halloween appearance token": 1068, + "Inverted Summoning Skillcape (120)": 610, + "Mallory pet halloween appearance token": 1069, + "Mask of the Matriarchs": 1070, + "Inverted Archaeology Skillcape (120)": 613, + "Inverted Divination Skillcape (120)": 611, + "Inverted Invention Skillcape (120)": 612, + "Frosty Shoulder Cape": 614, + "Frozen Shoulder Cape": 615, + "Terry Pet Token": 616, + "Amascut chapel token": 1073, + "Frozen Touch of Death cosmetic ability scroll": 1076, + "Santa Costume Gloves": 624, + "Santa Costume Legs": 622, + "Santa Costume Top": 621, + "Santa Costume Boots": 623, + "Aurora Dye": 619, + "Inverted Quest Cape": 625, + "Wand of the Cywir": 627, + "Inverted Ramsay Pet Token": 630, + "Inverted Gemi Pet Token": 631, + "Inverted Baby Yagas House Halo Pet Token": 629, + "Inverted Morty Halo Pet Token": 628, + "Inverted Wallace Halo Pet Token": 632, + "Virtus mask": 666, + "Virtus robe top": 667, + "Virtus robe legs": 668, + "Merciless kiteshield": 669, + "Torva full helm": 670, + "Torva platebody": 671, + "Torva platelegs": 672, + "Torva gloves": 673, + "Torva boots": 674, + "Wyrm spike": 675, + "Wyrm heart": 676, + "Wyrm scalp": 677, + "Wyvern crossbow": 678, + "Intricate smoke-shrouded chest": 679, + "Intricate shadow chest": 680, + "Intricate blood stained chest": 681, + "Intricate ice chest": 682, + "Second age full helm": 683, + "Elite sirenic mask": 684, + "Elite sirenic hauberk": 685, + "Elite sirenic chaps": 686, + "Elite tectonic mask": 687, + "Elite tectonic robe top": 688, + "Elite tectonic robe bottom": 689, + "Chaotic berserk cosmetic ability scroll": 702, + "Chaotic hurricane cosmetic ability scroll": 703, + "Azure sunshine cosmetic ability scroll": 704, + "Inverted Willow Halo Pet Token": 633, + "Inverted Gordie Halo Pet Token": 634, + "Inverted Brains Halo Pet Token": 635, + "Inverted Bernie Halo Pet Token": 636, + "Inverted Bubbles Halo Pet Token": 637, + "Inverted Herbert Halo Pet Token": 638, + "Inverted Ace Halo Pet Token": 639, + "Inverted Malcolm Halo Pet Token": 640, + "Inverted Rocky Halo Pet Token": 641, + "Inverted Ghostly Halo Pet Token": 642, + "Inverted Sparky Halo Pet Token": 643, + "Inverted Rue Halo Pet Token": 644, + "Inverted Crabbe Halo Pet Token": 645, + "Inverted Shamini Halo Pet Token": 646, + "Inverted Smithy Halo Pet Token": 647, + "Inverted Kangali Halo Pet Token": 648, + "Inverted Ralph Halo Pet Token": 649, + "Inverted Woody Halo Pet Token": 650, + "Inverted Newton Halo Pet Token": 651, + "Inverted Flo Halo Pet Token": 250, + "Orb of the Cywir elders": 652, + "Wand of the Cywir elders": 653, + "Merethiels stave": 699, + "Inverted Archie Pet Token": 448, + "Inverted Dojo Mojo Pet": 308, + "Infinity hat": 654, + "Infinity top": 655, + "Infinity gloves": 656, + "Infinity bottoms": 657, + "infinity boots": 658, + "Passage of the abyss": 659, + "Grace of the elves": 660, + "Spider leg": 661, + "Reaper Necklace": 662, + "Hydrix": 663, + "Infinity Robes Set": 664, + "Decimation": 665, + "Dormant Zaros Godsword": 700, + "Dormant Staff of Sliske": 701, + "Inverted Sifu Pet Token": 577, + "Pernix cowl": 705, + "Pernix body": 706, + "Pernix chaps": 707, + "Pernix gloves": 708, + "Pernix boots": 709, + "Mask of the Grove Guardian": 1071, + "Inverted Herblore Skillcape (120)": 604, + "Pirate hook (left)": 711, + "Pirate hook (right)": 712, + "Double pirate hooks": 713, + "Heart of the Warrior": 714, + "Heart of the Archer": 715, + "Rose tinted glasses": 716, + "Rose Petal Aura Token": 717, + "Warrior ring": 718, + "Seers' ring": 719, + "Amulet of fury": 720, + "Essence of finality ornament kit": 721, + "Reaper ornament kit": 722, + "Grasping rune pouch": 723, + "Tracking gloves": 724, + "Static gloves": 725, + "Double escape codex": 726, + "Pneumatic gloves": 727, + "Dragon mattock": 728, + "Dragon pickaxe": 729, + "Vengeful kiteshield": 730, + "Gloves of passage": 731, + "Jaws of the abyss": 732, + "Flarefrost boots": 733, + "Hailfire boots": 734, + "Emberkeen boots": 735, + "Virtus gloves": 736, + "Virtus boots": 737, + "Virtus wand": 738, + "Virtus book": 739, + "Shadow glaive": 740, + "Off-hand shadow glaive": 741, + "Lucky dragonkin coin": 742, + "Celestial handwraps": 743, + "Ascension grips": 744, + "Ragefire boots": 745, + "Steadfast boots": 746, + "Glaiven boots": 747, + "Annihilation": 748, + "Obliteration": 749, + "Undead slayer ability codex": 750, + "Dragon Slayer ability codex": 751, + "Mining and Smithing Flyer": 752, + "Steel Gauntlets (non-ge)": 753, + "Camel staff": 754, + "Pitch can (full)": 755, + "Demonic Title Scroll (General)": 756, + "Demoic Title SCroll (Terrifying)": 757, + "Demoic Title Scroll (deacon)": 758, + "Demonic Title Scroll (Blazing)": 759, + "Royal Shoulder Cape (Red)": 760, + "Royal Shoulder cape (Black)": 761, + "Dragon crested shoulder cape": 762, + "Noble shoulder cape": 763, + "Pumpkin Souls cosmetic ability scroll": 1072, + "Gud Raider Axe": 765, + "Soul ornament kit": 766, + "Heralds Hat Token": 767, + "Heralds Jacket and Gloves Token": 768, + "Heralds Trousers and Boots Token": 769, + "Heralds Gloves and Orb Token": 770, + "Second Age Mage Mask": 771, + "Ruby Suit token": 772, + "Emerald Suit token": 773, + "Diamond Suit token": 774, + "Vis wax": 775, + "Zigzag Easter egg": 776, + "Striped Easter egg": 777, + "Spotted Easter egg": 778, + "Spiky Easter egg": 779, + "Smooth Easter egg": 780, + "Intricate Easter egg": 781, + "Captain Deathbeard's Hook token": 812, + "Captain Deathbeard's Hat token": 813, + "Captain Deathbeard's Feet token": 814, + "Captain Deathbeard's Doublet token": 815, + "Captain Deathbeard's Breeches token": 816, + "Captain Deathbeard's (phantom) Outfit token": 817, + "Pirate sheep pet token": 818, + "Walk the Plank emote token": 819, + "Scurvy the cannon pet token": 820, + "Cursed amascut sand": 822, + "Amulet of the forsaken": 826, + "Dragon hatchet": 827, + "Fletching cleaner (inactive)": 828, + "Slayer Wildcard": 830, + "Artisanal gears": 832, + "Blood Ice Barricade cosmetic ability": 833, + "Golden cape": 831, + "Azure Reprisal cosmetic ability scroll": 834, + "Woody Bunny appearance token": 811, + "Willow Bunny appearance token": 810, + "Wallace Bunny appearance token": 809, + "Mizyuyari": 836, + "Soul witch token": 838, + "Primal Guardian (Phantom Guardian) cosmetic ability scroll": 1074, + "Mask of the Araxytes": 1086, + "Dragonfire shroud": 842, + "Omni guard": 843, + "Soulbound Lantern": 844, + "Crown of the First necromancer": 845, + "Food wraps of the First necromancer": 846, + "Hand wrap of the First Necromancer": 847, + "Robe bottom of the First Necromancer": 848, + "Robe top of the First Necromancer": 849, + "Greater ritual candle": 850, + "Powerful ghostly ink": 851, + "Greater flaming skull": 852, + "Running Scared Walk Override Token": 853, + "Boulder Pet token": 854, + "Hood of subjugation": 855, + "Garb of subjugation": 856, + "Gloves of subjugation": 857, + "Gown of subjugation": 858, + "Boots of subjugation": 859, + "Fungal Tendrils cosmetic ability scroll": 861, + "Fungal Assault cosmetic ability scroll": 862, + "Fungal Hurricane cosmetic ability scroll": 863, + "Enforcer walk override token": 865, + "Hedge Teleport token": 866, + "Ensouled pumpkin mask": 872, + "O lantern title scroll": 873, + "Soul Surge cosmetic ability scroll": 874, + "Soul dive cosmetic ability scroll": 875, + "Icthlarin chape token": 876, + "Pumpkin trees token": 877, + "Pumpkin beret override token": 878, + "Vorkath Necromancy weapon override token": 882, + "Elite Dracolich coif": 883, + "Elite Dracolich boots": 884, + "Elite Dracolich chaps": 885, + "Elite Dracolich hauberk": 886, + "Elite Dracolich vambraces": 887, + "Hexer Braids hairstyle token": 889, + "Invoke Lord of Bones incantation codex": 890, + "Purple Santa hat": 891, + "Magical Bunny egg": 892, + "Magical Lamb egg": 893, + "Magical Chick egg": 894, + "Festive Warrior (Skeleton Warrior) scroll": 896, + "Fairy Light Fishing token": 895, + "Winter Hat (Aurora)": 899, + "Winter Scarf (Aurora)": 900, + "Cherry blossom fan token": 902, + "Cherry blossom wand token": 903, + "Cherry blossom orb token": 904, + "emerald cane": 905, + "ruby cane": 906, + "Third Age Druidic Staff": 490, + "Jagex": 907, + "Frozen Basic Attack (Necromancy) cosmetic ability scroll": 1075, + "Soul Dye": 837, + "Orange Halloween Mask": 871, + "Black Partyhat": 880, + "Frozen Finger of Death cosmetic ability scroll": 1077, + "Crystal Keys": 1021, + "Fat Snail": 1022, + "Dolorous Witch hairstyle token": 1023, + "Zamorakian title scroll (The Witch)": 1024, + "Zamorakian title scroll (Acolyte)": 1025, + "Zamorakian title scroll (Hierophant)": 1026, + "Zamorakian title scroll (High Priest/Priestess)": 1027, + "Chaotic Assault cosmetic ability scroll": 1028, + "Fungal Swiftness cosmetic ability scroll": 1029, + "Azure Hurricane cosmetic ability scroll": 1030, + "Heart of the Berserker": 1031, + "Rainbow Dragonbreath cosmetic ability scroll": 1032, + "Omen Bunny appearance token": 1033, + "Power Flower Basket": 1034, + "Emerald cape": 1035, + "Ruby cape": 1036, + "Diamond cape": 1037, + "Shadow Gem Pernix Token": 1038, + "Gnome Goggles": 1039, + "Master Wand": 1040, + "Jail cell key": 1041, + "Occultist's ring": 1042, + "Corrupted Combust cosmetic ability scroll": 1043, + "Balarak's sash brush": 1044, + "Skeka's hypnowand": 1045, + "Rainbow trail aura override token": 1046, + "Casual Beachwear outfit token": 1047, + "Summer Warrior (Skeleton Warrior token)": 1048, + "Arcane apprentice umbrella token": 1049, + "Demonic Title Scroll (Deceiver)": 1050, + "Shard of Genesis Essence": 1053, + "Divine Rage prayer codex": 1054, + "Scripture of Amascut": 1055, + "Manuscript of Amascut": 1056, + "Frozen Death Skulls cosmetic ability scroll": 1078, + "Frozen Living Death cosmetic ability scroll": 1079, + "Warped Basic Attack (Necromancy) cosmetic ability scroll": 1080, + "Warped Touch of Death cosmetic ability scroll": 1081, + "Warped Finger of Death cosmetic ability scroll": 1082, + "Warped Death Skulls cosmetic ability scroll": 1083, + "Warped Living Death cosmetic ability scroll": 1084, + "Spectral lens": 1087, + "Pestilent Torva Armour Token": 1088, + "Shrouded Veil token": 1121, + "Faded Veil token": 1122, + "Pink Candy Cane Token": 1186, + "Orange Candy Cane Token": 1187, + "Cyan Candy Cane Token": 1188, + "Blue Candy Cane Token": 1189, + "Red Candy Cane Token": 1190, + "Green Candy Cane Token": 1191, + "Purple Candy Cane Token": 1192, + "Black Candy Cane Token": 1193, + "Festive Guardian cosmetic ability scroll": 1194, + "Festive Warrior (Set 2) scroll": 1195, + "Masterwork bow": 1219, + "Primal hatchet": 1220, + "Winter Sports Outfit token": 1222, + "A mis-fortune from The Mighty Zoltan 1-17 (set)": 1252, + "Black Christmas scythe": 1120, + "Pink Santa hat": 1153, + "Aurora Trail aura override token": 1221, + "Snowball Pet Token": 1286, + "Aurora Santa hat": 1285, + "Roar of Awakening": 1051, + "Ode to Deceit": 1052, + "Scripture of Elidinis": 1062, + "Ranger Roll Walk override token": 825, + "Azure Berserk cosmetic ability scroll": 835, + "Ice barricade cosmetic ability scroll": 824, + "Azure Swiftness cosmetic ability scroll": 823, + "Greater Sonic wave ability codex": 821, + "Sparky Bunny appearance token": 808, + "Smithy Bunny appearance token": 807, + "Sifu Bunny appearance token": 806, + "Shamini Bunny appearance token": 805, + "Rue Bunny appearance token": 804, + "Rocky Bunny appearance token": 803, + "Ramsay Bunny appearance token": 802, + "Ralph Bunny appearance token": 801, + "Newton Bunny appearance token": 800, + "Morty Bunny appearance token": 799, + "Malcolm Bunny appearance token": 798, + "Kangali Bunny appearance token": 797, + "Herbert Bunny appearance token": 796, + "Gordie Bunny appearance token": 795, + "Ghostly Bunny appearance token": 794, + "Gemi Bunny appearance token": 793, + "Flo Bunny appearance token": 792, + "Dojo Mojo Bunny appearance token": 791, + "Crabbe Bunny appearance token": 790, + "Bubbles Bunny appearance token": 789, + "Brains Bunny appearance token": 788, + "Bernie Bunny appearance token": 787, + "Baby yaga's House Bunny appearance token": 786, + "Archie Bunny appearance token": 785, + "Ace Bunny appearance token": 784, + "Full Easter basket": 783, + "Empty Easter basket": 782, + "Frozen Surge cosmetic ability scroll": 1318, + "Frozen Escape cosmetic ability scroll": 1319, + "Frozen Dive cosmetic ability scroll": 1320, + "Frozen Overpower cosmetic ability scroll": 1321, + "Frozen Deadshot cosmetic ability scroll": 1322, + "Frozen Omnipower cosmetic ability scroll": 1323, + "Warped Surge cosmetic ability scroll": 1324, + "Warped Escape cosmetic ability scroll": 1325, + "Warped Dive cosmetic ability scroll": 1326, + "Warped Overpower cosmetic ability scroll": 1327, + "Warped Deadshot cosmetic ability scroll": 1328, + "Warped Omnipower cosmetic ability scroll": 1329, + "Masterwork Staff": 1351, + "Vorkath's scale": 1352, + "Hellforged Warrior Armour Token": 1384, + "Dragonstone Circlet token": 1385, + "Onyx Circlet token": 1386, + "Hydrix Circlet token": 1387, + "Dragonstone title scroll": 1388, + "Onyx title scroll": 1389, + "Hydrix title scroll": 1390, + "Solid Gold Easter egg": 1391, + "Flower Basket Token": 1392, + "Chocolate Basket Token": 1393, + "Daisy Basket Token": 1394, + "Blue Flower Basket Token": 1395, + "Springbloom Hat token": 1417, + "Springbloom Staff token": 1418, + "Witch's Ride walk token": 1419, + "Springbloom Hime hairstyle token": 1420, + "Springbloom Aura token": 1421, + "Masterwork magic boots": 1450, + "Masterwork magic gloves": 1451, + "Masterwork magic hat": 1452, + "Masterwork magic robe bottom": 1453, + "Masterwork magic robe top": 1454, + "Dragonstone Gala Attire token": 1483, + "Onyx Gala Attire token": 1484, + "Hydrix Gala Attire token": 1485, + "Duskrunner's Hairstyle token": 1516, + "Duskrunner's Outfit token": 1517, + "Tumeken's Light": 1549, + "Devourer's Guard": 1550, + "Mask of Tumeken's resplendence": 1551, + "Robe top of Tumeken's resplendence": 1552, + "Boots of Tumeken's resplendence": 1553, + "Gloves of Tumeken's resplendence": 1554, + "Robe bottom of Tumeken's resplendence": 1555, + "The Devourer's Nexus (unattuned)": 1556, + "Tuska's Wrath ability codex": 1582, + "Heavenforged Warrior Armour Token": 1615, + "Chaotic crossbow frozen dye kit": 1616, + "Chaotic crossbow warped dye kit": 1617, + "Chaotic maul frozen dye kit": 1618, + "Chaotic maul warped dye kit": 1619, + "Chaotic rapier frozen dye kit": 1620, + "Chaotic rapier warped dye kit": 1621, + "Warped Kinship Teleport token": 1622, + "Warped Loot Beam token": 1623, + "Warped Trail token": 1624, + "Frozen Kinship Teleport token": 1625, + "Frozen Loot Beam token": 1626, + "Frozen Trail token": 1627, + "Shadowstep aura override token": 1628, + "Smokestep aura override token": 1629, + "Black pumpkin": 1630, + "Red pumpkin": 1631, + "Purple pumpkin": 1632, + "Black Ensouled pumpkin mask": 1633, + "Red Ensouled pumpkin mask": 1634, + "Bloodthirsty walk override token": 1635, + "Soul Escape cosmetic ability scroll": 1636, + "Blood soul witch token": 1637, + "lucille token": 1638, + "Witch's Outfit token": 1639, + "Batnado Teleport token": 1640, + "Yellow Hallowe'en mask": 1641, + "Soul dyed halloween mask": 1642, + "Blood Soul Surge cosmetic ability scroll": 1643, + "Blood Soul Dive cosmetic ability scroll": 1644, + "Blood Soul Escape cosmetic ability scroll": 1645, + "Catalyst Bloat cosmetic ability scroll": 1648, + "Catalyst Detonate cosmetic ability scroll": 1649, + "Catalyst Flurry cosmetic ability scroll": 1650, + "Catalyst Harpoon token": 1651, + "Catalyst Hatchet token": 1652, + "Catalyst Pickaxe token": 1653, + "Catalyst Reflect cosmetic ability scroll": 1654, + "Catalyst Relic hunter (tier 1) token": 1655, + "Catalyst Relic hunter (tier 2) token": 1656, + "Catalyst Relic hunter (tier 3) token": 1657, + "Catalyst Snap Shot cosmetic ability scroll": 1658, + "Catalyst aura token": 1659, + "Catalyst meditate rest token": 1660, + "Catalyst teleport token": 1661, + "Hexi pet token": 1662, + "Gloomfire bow": 1663, + "Legatus's Emberstaff": 1664, + "Misalionar's Death Mask": 1665, + "Varanus's Mercy": 1666, + "Black Giftwrapped Bow token": 1667, + "Black Giftwrapped Guard token": 1668, + "Black Giftwrapped Longsword token": 1669, + "Black Giftwrapped Staff token": 1670, + "Yellow Santa hat": 1671, + "Blue Santa hat": 1672, + "Moonlight Enchanter Robes token": 1673, + "Eclipse Enchanter Robes token": 1674, + "Deck Caster Woodcutting token": 1675, + "Cape of Devotion token": 1676, + "Cape of Devastation token": 1677, + "Symbol of Devotion token": 1678, + "Symbol of Devastation token": 1679, + "Blessed Wild Magic scroll": 1680, + "Corrupted Wild Magic scroll": 1681, + "Blessed Chain scroll": 1682, + "Corrupted Chain scroll": 1683, + "Blessed Concentrated Blast scroll": 1684, + "Corrupted Concentrated Blast scroll": 1685, + "Primal 2h Sword (Red) Token": 1686, + "Primal Pickaxe (Red) Token": 1687, + "Warped Daemonheim Armour Token": 1688, + "Dolorous Witch Outfit token": 1689, + "Tumeken Translocate token": 1690, + "Amascut Translocate token": 1691, + "Phoenix Knight Armour token": 1692, + "Dark Phoenix Knight Armour token": 1693, + "Visage of the First Necromancer": 1694, + "Am-hej": 1695, + "Jal-tok-yt": 1696, + "Ring of Vitur": 1697, + "Glacial Phoenix": 1698, + "Deadly Highwayman's Outfit (Master) token": 1699, + "Herald of Amascut Armour token": 1700, + "Herald of Tumeken Armour token": 1701, + "Black yo-yo": 1702, + "Yulemourne Armour Override Token": 1714, + "Yulemourne Greatsword Override Token": 1715, + "Frosted Tips hairstyle token": 1716, + "Dragon Harpoon": 1717, + "Stalker's charm": 1718, + "Nodon spike harness": 1719 +} \ No newline at end of file diff --git a/release/ely-extension-chrome.zip b/release/ely-extension-chrome.zip new file mode 100644 index 0000000..2278ce0 Binary files /dev/null and b/release/ely-extension-chrome.zip differ diff --git a/release/ely-extension-firefox.zip b/release/ely-extension-firefox.zip new file mode 100644 index 0000000..8cb23bc Binary files /dev/null and b/release/ely-extension-firefox.zip differ diff --git a/release/ely-userscript.user.js b/release/ely-userscript.user.js new file mode 100644 index 0000000..d55ca5f --- /dev/null +++ b/release/ely-userscript.user.js @@ -0,0 +1,258 @@ +// ==UserScript== +// @name RuneScape Wiki Ely Prices +// @namespace https://ely.gg/ +// @version 1.0.1 +// @description Show Ely prices on RuneScape Wiki pages +// @match https://runescape.wiki/w/* +// @grant GM_xmlhttpRequest +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_registerMenuCommand +// @connect www.ely.gg +// @connect git.yorgei.dev +// @connect * +// @downloadURL https://git.yorgei.dev/yorgei/rs-wiki-ely/raw/branch/main/script.user.js +// ==/UserScript== + +(async function () { + const defaultUrl = 'https://git.yorgei.dev/yorgei/rs-wiki-ely/raw/branch/main/new_data.json'; + const dataUrl = GM_getValue('elyDataUrl', defaultUrl); + + GM_registerMenuCommand('Set Custom Data URL', () => { + const currentUrl = GM_getValue('elyDataUrl', defaultUrl); + const newUrl = prompt('Enter custom data JSON URL:', currentUrl); + if (newUrl) { + GM_setValue('elyDataUrl', newUrl); + alert('Data URL updated! Refresh the page to apply changes.'); + } + }); + + function getCacheBustingUrl(url) { + return `${url}?t=${Date.now()}`; + } + + 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 itemData = await gmFetchJson(getCacheBustingUrl(dataUrl)); + + const pageTitle = pageTitleElement.textContent.trim(); + const urlPath = window.location.pathname; + const urlTitle = urlPath.replace('/w/', '').replace(/_/g, ' '); + console.log(pageTitle, urlTitle, urlPath); + + 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 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..1190bd8 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +beautifulsoup4 diff --git a/userscript.js b/userscript.js new file mode 100644 index 0000000..d55ca5f --- /dev/null +++ b/userscript.js @@ -0,0 +1,258 @@ +// ==UserScript== +// @name RuneScape Wiki Ely Prices +// @namespace https://ely.gg/ +// @version 1.0.1 +// @description Show Ely prices on RuneScape Wiki pages +// @match https://runescape.wiki/w/* +// @grant GM_xmlhttpRequest +// @grant GM_setValue +// @grant GM_getValue +// @grant GM_registerMenuCommand +// @connect www.ely.gg +// @connect git.yorgei.dev +// @connect * +// @downloadURL https://git.yorgei.dev/yorgei/rs-wiki-ely/raw/branch/main/script.user.js +// ==/UserScript== + +(async function () { + const defaultUrl = 'https://git.yorgei.dev/yorgei/rs-wiki-ely/raw/branch/main/new_data.json'; + const dataUrl = GM_getValue('elyDataUrl', defaultUrl); + + GM_registerMenuCommand('Set Custom Data URL', () => { + const currentUrl = GM_getValue('elyDataUrl', defaultUrl); + const newUrl = prompt('Enter custom data JSON URL:', currentUrl); + if (newUrl) { + GM_setValue('elyDataUrl', newUrl); + alert('Data URL updated! Refresh the page to apply changes.'); + } + }); + + function getCacheBustingUrl(url) { + return `${url}?t=${Date.now()}`; + } + + 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 itemData = await gmFetchJson(getCacheBustingUrl(dataUrl)); + + const pageTitle = pageTitleElement.textContent.trim(); + const urlPath = window.location.pathname; + const urlTitle = urlPath.replace('/w/', '').replace(/_/g, ' '); + console.log(pageTitle, urlTitle, urlPath); + + 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