This commit is contained in:
Yorgei
2026-01-18 14:29:12 +10:00
commit e23ac642a7
21 changed files with 3370 additions and 0 deletions

View File

@@ -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;
}
});
}

257
chrome-extension/content.js Normal file
View File

@@ -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);
}
});
}
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
chrome-extension/img/64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -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"
]
}

View File

@@ -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
}
}

View File

@@ -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
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<title>Ely Wiki Extension Options</title>
<style>
body {
font-family: sans-serif;
padding: 20px;
min-width: 300px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"] {
width: 100%;
padding: 8px;
box-sizing: border-box;
margin-bottom: 10px;
}
button {
padding: 8px 16px;
background-color: #5a8c5a;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #487048;
}
.status {
margin-top: 10px;
font-size: 0.9em;
color: green;
}
.note {
font-size: 0.8em;
color: #666;
margin-top: 20px;
}
</style>
</head>
<body>
<label for="dataUrl">Custom Data JSON URL:</label>
<input type="text" id="dataUrl" placeholder="Leave empty to use default local data">
<button id="save">Save</button>
<div id="status" class="status"></div>
<div class="note">
Leave empty to use the bundled extension data. <br>
Should link to the raw json file of items.
</div>
<script src="options.js"></script>
</body>
</html>

View File

@@ -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;
}
});
});