您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
View items you are searching for in registered bazaars!
当前为
// ==UserScript== // @name Bazaar Item Search powered by IronNerd // @namespace [email protected] // @version 0.3 // @description View items you are searching for in registered bazaars! // @author Nurv [669537] // @match https://www.torn.com/page.php?sid=ItemMarket* // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @run-at document-end // @license Copyright IronNerd.me // @connect ironnerd.me // ==/UserScript== (function() { 'use strict'; console.log('IronNerd Bazaar Enhancements script started.'); init(); async function init() { addSettingsButton(); addOneDollarButton(); injectAdditionalStyles(); const apiKey = await GM_getValue('tornApiKey', ''); if (apiKey) { checkBazaarStatus(apiKey); } detectSearch(); } function addSettingsButton() { const intervalId = setInterval(() => { const linksContainer = document.querySelector('.linksContainer___LiOTN'); if (linksContainer) { clearInterval(intervalId); const button = document.createElement('button'); button.setAttribute('type', 'button'); button.className = 'linkContainer___X16y4 inRow___VfDnd greyLineV___up8VP iconActive___oAum9'; button.style.cursor = 'pointer'; button.style.display = 'flex'; button.style.alignItems = 'center'; button.style.justifyContent = 'center'; button.style.padding = '8px'; const iconWrapper = document.createElement('span'); iconWrapper.className = 'iconWrapper___x3ZLe iconWrapper___COKJD svgIcon___IwbJV'; iconWrapper.style.display = 'flex'; iconWrapper.style.alignItems = 'center'; iconWrapper.style.justifyContent = 'center'; const gearIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); gearIcon.setAttribute('width', '24'); gearIcon.setAttribute('height', '24'); gearIcon.setAttribute('viewBox', '0 0 24 24'); gearIcon.setAttribute('fill', 'currentColor'); gearIcon.innerHTML = ` <path d="M19.14,12.936l1.843-1.061a0.5,0.5,0,0,0,.11-0.63l-1.741-3.012a0.5,0.5,0,0,0-.61-0.22l-2.169,0.875a7.056,7.056,0,0,0-1.607-0.93l-0.33-2.313A0.5,0.5,0,0,0,13.5,4H10.5a0.5,0.5,0,0,0-.49,0.42l-0.33,2.313a7.056,7.056,0,0,0-1.607,0.93l-2.169-0.875a0.5,0.5,0,0,0-.61,0.22L3.56,11.245a0.5,0.5,0,0,0,.11,0.63l1.843,1.061a7.154,7.154,0,0,0,0,1.872L3.67,16.936a0.5,0.5,0,0,0-.11,0.63l1.741,3.012a0.5,0.5,0,0,0,.61,0.22l2.169-0.875a7.056,7.056,0,0,0,1.607,0.93l0.33,2.313a0.5,0.5,0,0,0,.49,0.42h3a0.5,0.5,0,0,0,.49-0.42l0.33-2.313a7.056,7.056,0,0,0,1.607-0.93l2.169,0.875a0.5,0.5,0,0,0,.61-0.22l1.741-3.012a0.5,0.5,0,0,0-.11-0.63Zm-7.14,2.064A3,3,0,1,1,15,12,3,3,0,0,1,12,15Z"/> `; iconWrapper.appendChild(gearIcon); button.appendChild(iconWrapper); button.addEventListener('click', openSettingsModal); linksContainer.appendChild(button); console.log('IronNerd Bazaar Enhancements: Settings button added.'); } }, 500); } async function openSettingsModal() { let existingModal = document.getElementById('bazaar-enhancer-modal'); if (existingModal) { document.body.removeChild(existingModal); } const savedApiKey = await GM_getValue('tornApiKey', ''); const modal = document.createElement('div'); modal.id = 'bazaar-enhancer-modal'; modal.setAttribute('role', 'dialog'); modal.setAttribute('aria-labelledby', 'modal-title'); modal.setAttribute('aria-modal', 'true'); modal.style = 'position: fixed; top: 0; left: 0; width: 100%; height: 100%;' + 'background-color: rgba(0,0,0,0.5); z-index: 1001; display: flex; align-items: center; justify-content: center;'; modal.innerHTML = ` <div id="modal-content" style="background-color: #fff; padding: 20px; border-radius: 5px; width: 400px; position: relative;"> <h2 id="modal-title">Bazaar Enhancer Settings</h2> <label for="apiKey">Your Torn API Key:</label><br> <input type="password" id="apiKey" style="width: 100%; border: 1px solid #ccc; border-radius: 5px;" value="${savedApiKey}"><br> <input type="checkbox" id="toggleVisibility"> <label for="toggleVisibility">Show API Key</label><br><br> <button id="saveApiKey">Save API Key</button> <button id="registerBazaar">Register Bazaar</button> <button id="removeBazaar">Remove Bazaar</button><br><br> <div id="statusMessage" style="margin-top: 10px; font-weight: bold;"></div> <button id="closeModal" style="position: absolute; top: 10px; right: 10px;" aria-label="Close Modal">×</button> </div> `; document.body.appendChild(modal); applyThemeToModal(modal); trapFocus(modal); const toggleVisibility = modal.querySelector('#toggleVisibility'); const apiKeyInput = modal.querySelector('#apiKey'); toggleVisibility.addEventListener('change', () => { apiKeyInput.type = toggleVisibility.checked ? 'text' : 'password'; }); modal.querySelector('#saveApiKey').addEventListener('click', async () => { const apiKey = apiKeyInput.value.trim(); const saveButton = modal.querySelector('#saveApiKey'); if (apiKey) { if (!isValidApiKey(apiKey)) { displayStatusMessage('error', 'Invalid API key format. Please check and try again.'); return; } saveButton.disabled = true; const spinner = createLoadingSpinner(); saveButton.parentNode.insertBefore(spinner, saveButton.nextSibling); try { await GM_setValue('tornApiKey', apiKey); displayStatusMessage('success', 'API key saved successfully.'); checkBazaarStatus(apiKey); } catch (error) { displayStatusMessage('error', 'Failed to save API key.'); console.error(error); } finally { saveButton.disabled = false; spinner.remove(); } } else { displayStatusMessage('error', 'Please enter a valid API key.'); } }); modal.querySelector('#registerBazaar').addEventListener('click', async () => { const apiKey = await GM_getValue('tornApiKey', ''); if (apiKey) { registerApiKey(apiKey); } else { displayStatusMessage('error', 'Please save your API key first.'); } }); modal.querySelector('#removeBazaar').addEventListener('click', async () => { const apiKey = await GM_getValue('tornApiKey', ''); if (apiKey) { unregisterApiKey(apiKey); } else { displayStatusMessage('error', 'No API key found to remove.'); } }); modal.querySelector('#closeModal').addEventListener('click', () => { closeSettingsModal(); }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape') { const modal = document.getElementById('bazaar-enhancer-modal'); if (modal) { closeSettingsModal(); } } }); const observer = new MutationObserver(() => { applyThemeToModal(modal); }); observer.observe(document.body, { attributes: true, attributeFilter: ['class'] }); apiKeyInput.focus(); } function closeSettingsModal() { const modal = document.getElementById('bazaar-enhancer-modal'); if (modal) { document.body.removeChild(modal); console.log('IronNerd Bazaar Enhancements: Settings modal closed.'); } } function applyThemeToModal(modal) { const isDarkMode = document.body.classList.contains('darkMode___3kucI'); const modalContent = modal.querySelector('#modal-content'); if (isDarkMode) { modalContent.style.backgroundColor = '#2c2c2c'; modalContent.style.color = '#f0f0f0'; modalContent.querySelectorAll('button').forEach(btn => { btn.style.backgroundColor = '#444'; btn.style.color = '#f0f0f0'; btn.style.border = 'none'; btn.style.padding = '8px 12px'; btn.style.marginRight = '5px'; btn.style.borderRadius = '3px'; }); modalContent.querySelector('h2').style.color = '#f0f0f0'; } else { modalContent.style.backgroundColor = '#fff'; modalContent.style.color = '#000'; modalContent.querySelectorAll('button').forEach(btn => { btn.style.backgroundColor = '#f2f2f2'; btn.style.color = '#000'; btn.style.border = '1px solid #ccc'; btn.style.padding = '8px 12px'; btn.style.marginRight = '5px'; btn.style.borderRadius = '3px'; }); modalContent.querySelector('h2').style.color = '#000'; } const statusDiv = modal.querySelector('#statusMessage'); if (statusDiv) { statusDiv.style.transition = 'background-color 0.3s, color 0.3s'; } } function trapFocus(modal) { const focusableElements = modal.querySelectorAll('a[href], button, textarea, input, select'); const firstFocusable = focusableElements[0]; const lastFocusable = focusableElements[focusableElements.length - 1]; modal.addEventListener('keydown', function(e) { const isTabPressed = (e.key === 'Tab' || e.keyCode === 9); if (!isTabPressed) return; if (e.shiftKey) { if (document.activeElement === firstFocusable) { lastFocusable.focus(); e.preventDefault(); } } else { if (document.activeElement === lastFocusable) { firstFocusable.focus(); e.preventDefault(); } } }); } function createLoadingSpinner() { const spinner = document.createElement('div'); spinner.className = 'loading-spinner'; spinner.style.border = '4px solid #f3f3f3'; spinner.style.borderTop = '4px solid #3498db'; spinner.style.borderRadius = '50%'; spinner.style.width = '24px'; spinner.style.height = '24px'; spinner.style.animation = 'spin 2s linear infinite'; spinner.style.display = 'inline-block'; spinner.style.marginLeft = '10px'; return spinner; } function injectAdditionalStyles() { const style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = ` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } /* Modal Scrollbar Styling */ #oneDollarModal::-webkit-scrollbar { width: 12px; } #oneDollarModal::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 6px; } #oneDollarModal::-webkit-scrollbar-thumb { background: #888; border-radius: 6px; } #oneDollarModal::-webkit-scrollbar-thumb:hover { background: #555; } /* Table Hover Effect */ #oneDollarModal table tr:hover { background-color: #ddd; } /* Responsive Table */ @media screen and (max-width: 600px) { #oneDollarModal table, #oneDollarModal table thead, #oneDollarModal table tbody, #oneDollarModal table th, #oneDollarModal table td, #oneDollarModal table tr { display: block; } #oneDollarModal table tr { margin-bottom: 15px; } #oneDollarModal table th { display: none; } #oneDollarModal table td { text-align: right; padding-left: 50%; position: relative; } #oneDollarModal table td::before { content: attr(data-label); position: absolute; left: 0; width: 50%; padding-left: 15px; font-weight: bold; text-align: left; } } /* Dark Mode Styles for $1 Items Modal */ .darkMode___3kucI #oneDollarModal table, .darkMode___3kucI #oneDollarModal th, .darkMode___3kucI #oneDollarModal td { background-color: #1c1c1c; color: #f0f0f0; } .darkMode___3kucI #oneDollarModal th { background-color: #333; } .darkMode___3kucI #oneDollarModal tr:nth-child(even) { background-color: #2a2a2a; } .darkMode___3kucI #oneDollarModal tr:nth-child(odd) { background-color: #1e1e1e; } /* Additional Styles for Improved Mobile View */ @media screen and (max-width: 600px) { #oneDollarModal table { border: none; } #oneDollarModal table tr { border-bottom: 1px solid #ccc; padding-bottom: 10px; } #oneDollarModal table td { border: none; border-bottom: 1px solid #eee; padding: 8px 0; } #oneDollarModal table td:last-child { border-bottom: none; } } /* Smooth Transition for Hover Effects */ #oneDollarModal table tr, #oneDollarModal table td, #oneDollarModal table th { transition: background-color 0.3s, color 0.3s; } `; document.head.appendChild(style); console.log('IronNerd Bazaar Enhancements: Additional styles injected.'); } function addOneDollarButton() { const intervalId = setInterval(() => { const linksContainer = document.querySelector('.linksContainer___LiOTN'); if (linksContainer) { clearInterval(intervalId); const button = document.createElement('button'); button.id = 'oneDollarSearchBtn'; button.innerText = '$1'; button.style.cursor = 'pointer'; button.style.padding = '8px 12px'; button.style.marginLeft = '10px'; button.style.backgroundColor = '#ff5722'; button.style.color = '#fff'; button.style.border = 'none'; button.style.borderRadius = '4px'; button.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.2)'; button.style.fontSize = '14px'; const dollarIcon = document.createElement('span'); dollarIcon.innerHTML = '$'; dollarIcon.style.marginRight = '5px'; button.prepend(dollarIcon); linksContainer.appendChild(button); button.addEventListener('click', openOneDollarModal); console.log('IronNerd Bazaar Enhancements: "$1 Items" button added.'); } }, 500); } function openOneDollarModal() { console.log('IronNerd Bazaar Enhancements: "$1 Items" button clicked.'); createOneDollarModal(); const modal = document.getElementById('oneDollarModal'); if (modal) { modal.style.display = 'block'; fetchOneDollarItems(); trapFocus(modal); } else { console.error('IronNerd Bazaar Enhancements: oneDollarModal element not found.'); } } function createOneDollarModal() { if (document.getElementById('oneDollarModal')) { console.log('IronNerd Bazaar Enhancements: $1 Items modal already exists.'); return; } console.log('IronNerd Bazaar Enhancements: Creating $1 Items modal.'); const overlay = document.createElement('div'); overlay.id = 'oneDollarModal'; overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; overlay.style.width = '100%'; overlay.style.height = '100%'; overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; overlay.style.display = 'none'; overlay.style.zIndex = '10000'; overlay.style.overflowY = 'auto'; const modalContent = document.createElement('div'); modalContent.style.backgroundColor = '#fff'; modalContent.style.margin = '50px auto'; modalContent.style.padding = '20px'; modalContent.style.borderRadius = '8px'; modalContent.style.width = '90%'; modalContent.style.maxWidth = '800px'; modalContent.style.position = 'relative'; modalContent.style.boxShadow = '0 5px 15px rgba(0,0,0,0.3)'; const closeBtn = document.createElement('span'); closeBtn.innerHTML = '×'; closeBtn.style.position = 'absolute'; closeBtn.style.top = '10px'; closeBtn.style.right = '20px'; closeBtn.style.fontSize = '30px'; closeBtn.style.fontWeight = 'bold'; closeBtn.style.cursor = 'pointer'; closeBtn.style.color = '#aaa'; closeBtn.addEventListener('mouseover', () => { closeBtn.style.color = '#000'; }); closeBtn.addEventListener('mouseout', () => { closeBtn.style.color = '#aaa'; }); closeBtn.addEventListener('click', closeOneDollarModal); const title = document.createElement('h2'); title.innerText = '$1 Items in Bazaar'; title.style.textAlign = 'center'; title.style.marginBottom = '20px'; const sortContainer = document.createElement('div'); sortContainer.style.textAlign = 'right'; sortContainer.style.marginBottom = '10px'; const sortLabel = document.createElement('label'); sortLabel.innerText = 'Sort by Market Price: '; sortLabel.setAttribute('for', 'sortSelect'); const sortSelect = document.createElement('select'); sortSelect.id = 'sortSelect'; sortSelect.style.padding = '5px'; sortSelect.style.marginLeft = '10px'; const optionAsc = document.createElement('option'); optionAsc.value = 'market_price_asc'; optionAsc.text = 'Low to High'; const optionDesc = document.createElement('option'); optionDesc.value = 'market_price_desc'; optionDesc.text = 'High to Low'; sortSelect.add(optionAsc); sortSelect.add(optionDesc); sortContainer.appendChild(sortLabel); sortContainer.appendChild(sortSelect); const resultsContainer = document.createElement('div'); resultsContainer.id = 'oneDollarResults'; resultsContainer.style.marginTop = '20px'; modalContent.appendChild(closeBtn); modalContent.appendChild(title); modalContent.appendChild(sortContainer); modalContent.appendChild(resultsContainer); overlay.appendChild(modalContent); document.body.appendChild(overlay); console.log('IronNerd Bazaar Enhancements: $1 Items modal created and appended to the DOM.'); } function closeOneDollarModal() { const modal = document.getElementById('oneDollarModal'); if (modal) { modal.style.display = 'none'; console.log('IronNerd Bazaar Enhancements: $1 Items modal closed.'); } } function fetchOneDollarItems() { const backendUrl = 'https://www.ironnerd.me/search_one_dollar'; let sortOrder = 'market_price_asc'; getOneDollarItems(sortOrder); const sortSelect = document.getElementById('sortSelect'); sortSelect.addEventListener('change', () => { sortOrder = sortSelect.value; getOneDollarItems(sortOrder); }); } function getOneDollarItems(sortOrder) { const resultsContainer = document.getElementById('oneDollarResults'); resultsContainer.innerHTML = '<p>Loading...</p>'; GM_xmlhttpRequest({ method: 'GET', url: `https://www.ironnerd.me/search_one_dollar?sort=${sortOrder}`, headers: { 'Accept': 'application/json' }, onload: function(response) { if (response.status === 200) { try { const data = JSON.parse(response.responseText); displayOneDollarItems(data.bazaar_items); console.log('IronNerd Bazaar Enhancements: $1 Items data fetched successfully.'); } catch (e) { resultsContainer.innerHTML = '<p>Error parsing server response.</p>'; console.error('IronNerd Bazaar Enhancements: Parsing Error:', e); } } else { resultsContainer.innerHTML = `<p>Error: ${response.status} - ${response.statusText}</p>`; console.error('IronNerd Bazaar Enhancements: Fetch $1 Items Error:', response.responseText); } }, onerror: function(error) { resultsContainer.innerHTML = '<p>Network error occurred. Please try again later.</p>'; console.error('IronNerd Bazaar Enhancements: Network Error:', error); } }); } function displayOneDollarItems(items) { const resultsContainer = document.getElementById('oneDollarResults'); resultsContainer.innerHTML = ''; if (!items || items.length === 0) { resultsContainer.innerHTML = '<p>No $1 items found.</p>'; return; } const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); const headers = ['Owner', 'Item Name', 'Type', 'Quantity', 'Price ($)', 'Market Price ($)', 'Updated At', 'Visit Bazaar']; headers.forEach(headerText => { const th = document.createElement('th'); th.innerText = headerText; th.style.border = '1px solid #ddd'; th.style.padding = '8px'; th.style.backgroundColor = '#f2f2f2'; th.style.textAlign = 'center'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); const tbody = document.createElement('tbody'); items.forEach(itemData => { const item = itemData.item; const tr = document.createElement('tr'); const ownerTd = document.createElement('td'); ownerTd.innerText = itemData.owner; ownerTd.setAttribute('data-label', 'Owner'); ownerTd.style.border = '1px solid #ddd'; ownerTd.style.padding = '8px'; ownerTd.style.textAlign = 'center'; tr.appendChild(ownerTd); const nameTd = document.createElement('td'); nameTd.innerText = item.name; nameTd.setAttribute('data-label', 'Item Name'); nameTd.style.border = '1px solid #ddd'; nameTd.style.padding = '8px'; nameTd.style.textAlign = 'center'; tr.appendChild(nameTd); const typeTd = document.createElement('td'); typeTd.innerText = item.type || 'N/A'; typeTd.setAttribute('data-label', 'Type'); typeTd.style.border = '1px solid #ddd'; typeTd.style.padding = '8px'; typeTd.style.textAlign = 'center'; tr.appendChild(typeTd); const quantityTd = document.createElement('td'); quantityTd.innerText = item.quantity; quantityTd.setAttribute('data-label', 'Quantity'); quantityTd.style.border = '1px solid #ddd'; quantityTd.style.padding = '8px'; quantityTd.style.textAlign = 'center'; tr.appendChild(quantityTd); const priceTd = document.createElement('td'); priceTd.innerText = `$${item.price.toLocaleString()}`; priceTd.setAttribute('data-label', 'Price ($)'); priceTd.style.border = '1px solid #ddd'; priceTd.style.padding = '8px'; priceTd.style.textAlign = 'center'; tr.appendChild(priceTd); const marketPriceTd = document.createElement('td'); marketPriceTd.innerText = item.market_price ? `$${item.market_price.toLocaleString()}` : 'N/A'; marketPriceTd.setAttribute('data-label', 'Market Price ($)'); marketPriceTd.style.border = '1px solid #ddd'; marketPriceTd.style.padding = '8px'; marketPriceTd.style.textAlign = 'center'; tr.appendChild(marketPriceTd); const updatedAtTd = document.createElement('td'); updatedAtTd.innerText = item.updated_at; updatedAtTd.setAttribute('data-label', 'Updated At'); updatedAtTd.style.border = '1px solid #ddd'; updatedAtTd.style.padding = '8px'; updatedAtTd.style.textAlign = 'center'; tr.appendChild(updatedAtTd); const bazaarTd = document.createElement('td'); bazaarTd.style.border = '1px solid #ddd'; bazaarTd.style.padding = '8px'; bazaarTd.style.textAlign = 'center'; const bazaarLink = document.createElement('a'); bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${itemData.user_id}`; bazaarLink.textContent = 'Visit'; bazaarLink.target = '_blank'; bazaarLink.style.color = '#007bff'; bazaarLink.style.textDecoration = 'none'; bazaarLink.addEventListener('mouseover', () => { bazaarLink.style.textDecoration = 'underline'; }); bazaarLink.addEventListener('mouseout', () => { bazaarLink.style.textDecoration = 'none'; }); bazaarTd.appendChild(bazaarLink); bazaarTd.setAttribute('data-label', 'Visit Bazaar'); tr.appendChild(bazaarTd); tbody.appendChild(tr); }); table.appendChild(tbody); resultsContainer.appendChild(table); adjustOneDollarTableTheme(); } function adjustOneDollarTableTheme() { const isDarkMode = document.body.classList.contains('darkMode___3kucI'); const table = document.querySelector('#oneDollarResults table'); if (isDarkMode && table) { table.style.backgroundColor = '#1c1c1c'; table.style.color = '#f0f0f0'; table.querySelectorAll('th').forEach(th => { th.style.backgroundColor = '#333'; th.style.color = '#f0f0f0'; }); table.querySelectorAll('tr:nth-child(even)').forEach(tr => { tr.style.backgroundColor = '#2a2a2a'; }); table.querySelectorAll('tr:nth-child(odd)').forEach(tr => { tr.style.backgroundColor = '#1e1e1e'; }); } else if (table) { table.style.backgroundColor = '#fff'; table.style.color = '#000'; table.querySelectorAll('th').forEach(th => { th.style.backgroundColor = '#f2f2f2'; th.style.color = '#000'; }); table.querySelectorAll('tr:nth-child(even)').forEach(tr => { tr.style.backgroundColor = '#f9f9f9'; }); table.querySelectorAll('tr:nth-child(odd)').forEach(tr => { tr.style.backgroundColor = '#fff'; }); } } function registerApiKey(apiKey) { console.log('IronNerd Bazaar Enhancements: Registering API Key:', apiKey); const modal = document.getElementById('bazaar-enhancer-modal'); const registerButton = modal.querySelector('#registerBazaar'); registerButton.disabled = true; const spinner = createLoadingSpinner(); registerButton.parentNode.insertBefore(spinner, registerButton.nextSibling); GM_xmlhttpRequest({ method: 'POST', url: 'https://www.ironnerd.me/add_bazaar_api_key', headers: { 'Content-Type': 'application/json' }, data: JSON.stringify({ api_key: apiKey }), onload: function(response) { spinner.remove(); registerButton.disabled = false; console.log('IronNerd Bazaar Enhancements: Response Status:', response.status); console.log('IronNerd Bazaar Enhancements: Response Text:', response.responseText); try { const data = JSON.parse(response.responseText); if (response.status === 201) { displayStatusMessage('success', 'Bazaar registered successfully.'); } else if (response.status === 200) { if (data.status === 'info') { displayStatusMessage('info', data.message); } else { displayStatusMessage('error', data.message || 'Error registering bazaar.'); } } else if (response.status === 403) { displayStatusMessage('error', data.message || 'Registration forbidden.'); } else { displayStatusMessage('error', 'Error registering bazaar.'); console.error('IronNerd Bazaar Enhancements: Register Bazaar Error:', response.responseText); } } catch (e) { displayStatusMessage('error', 'Unexpected response format.'); console.error('IronNerd Bazaar Enhancements: Parsing Error:', e); } }, onerror: function(error) { spinner.remove(); registerButton.disabled = false; displayStatusMessage('error', 'Network error occurred. Please try again later.'); console.error('IronNerd Bazaar Enhancements: Network Error:', error); } }); } function unregisterApiKey(apiKey) { console.log('IronNerd Bazaar Enhancements: Unregistering API Key:', apiKey); const modal = document.getElementById('bazaar-enhancer-modal'); const removeButton = modal.querySelector('#removeBazaar'); removeButton.disabled = true; const spinner = createLoadingSpinner(); removeButton.parentNode.insertBefore(spinner, removeButton.nextSibling); GM_xmlhttpRequest({ method: 'POST', url: 'https://www.ironnerd.me/remove_bazaar_api_key', headers: { 'Content-Type': 'application/json' }, data: JSON.stringify({ api_key: apiKey }), onload: function(response) { spinner.remove(); removeButton.disabled = false; console.log('IronNerd Bazaar Enhancements: Response Status:', response.status); console.log('IronNerd Bazaar Enhancements: Response Text:', response.responseText); try { const data = JSON.parse(response.responseText); if (response.status === 200) { displayStatusMessage('success', 'Bazaar removed successfully.'); GM_setValue('tornApiKey', ''); modal.querySelector('#apiKey').value = ''; } else { displayStatusMessage('error', data.message || 'Error removing bazaar.'); console.error('IronNerd Bazaar Enhancements: Unregister Bazaar Error:', response.responseText); } } catch (e) { displayStatusMessage('error', 'Unexpected response format.'); console.error('IronNerd Bazaar Enhancements: Parsing Error:', e); } }, onerror: function(error) { spinner.remove(); removeButton.disabled = false; displayStatusMessage('error', 'Network error occurred. Please try again later.'); console.error('IronNerd Bazaar Enhancements: Network Error:', error); } }); } function checkBazaarStatus(apiKey) { console.log('IronNerd Bazaar Enhancements: Checking Bazaar Status for API Key:', apiKey); GM_xmlhttpRequest({ method: 'POST', url: 'https://www.ironnerd.me/check_bazaar_status', headers: { 'Content-Type': 'application/json' }, data: JSON.stringify({ api_key: apiKey }), onload: function(response) { console.log('IronNerd Bazaar Enhancements: Check Status Response Status:', response.status); console.log('IronNerd Bazaar Enhancements: Check Status Response Text:', response.responseText); try { const data = JSON.parse(response.responseText); if (response.status === 200) { if (data.status === 'info') { displayStatusMessage('info', data.message); } else { displayStatusMessage('error', data.message || 'Error checking bazaar status.'); } } else { displayStatusMessage('error', 'Error checking bazaar status.'); console.error('IronNerd Bazaar Enhancements: Check Bazaar Status Error:', response.responseText); } } catch (e) { displayStatusMessage('error', 'Unexpected response format.'); console.error('IronNerd Bazaar Enhancements: Parsing Error:', e); } }, onerror: function(error) { displayStatusMessage('error', 'Network error occurred. Please try again later.'); console.error('IronNerd Bazaar Enhancements: Network Error:', error); } }); } function displayStatusMessage(status, message) { const modal = document.getElementById('bazaar-enhancer-modal'); const statusDiv = modal.querySelector('#statusMessage'); if (!statusDiv) return; statusDiv.innerHTML = ''; const icon = document.createElement('span'); icon.style.marginRight = '8px'; if (status === 'success') { icon.textContent = '✅'; statusDiv.style.color = '#155724'; statusDiv.style.backgroundColor = '#d4edda'; } else if (status === 'error') { icon.textContent = '❌'; statusDiv.style.color = '#721c24'; statusDiv.style.backgroundColor = '#f8d7da'; } else if (status === 'info') { icon.textContent = 'ℹ️'; statusDiv.style.color = '#004085'; statusDiv.style.backgroundColor = '#cce5ff'; } const messageSpan = document.createElement('span'); messageSpan.textContent = message; statusDiv.appendChild(icon); statusDiv.appendChild(messageSpan); statusDiv.style.padding = '5px'; statusDiv.style.borderRadius = '3px'; statusDiv.style.display = 'flex'; statusDiv.style.alignItems = 'center'; statusDiv.style.transition = 'background-color 0.3s, color 0.3s'; setTimeout(() => { statusDiv.textContent = ''; statusDiv.style.display = 'none'; }, 5000); } function displayErrorMessage(message) { displayStatusMessage('error', message); } function detectSearch() { window.addEventListener('hashchange', onHashChange, false); window.addEventListener('popstate', onHashChange, false); onHashChange(); } function onHashChange() { const itemName = getItemNameFromUrl(); if (itemName) { fetchBazaarItems(itemName); } } function getItemNameFromUrl() { let itemName = null; const hash = window.location.hash; if (hash && hash.includes('itemName=')) { const hashParams = new URLSearchParams(hash.substring(hash.indexOf('?') + 1)); itemName = hashParams.get('itemName'); console.log('IronNerd Bazaar Enhancements: Extracted itemName from hash:', itemName); } if (!itemName) { const searchParams = new URLSearchParams(window.location.search); itemName = searchParams.get('itemName'); console.log('IronNerd Bazaar Enhancements: Extracted itemName from search:', itemName); } if (itemName) { return decodeURIComponent(itemName.replace(/\+/g, ' ')); } return null; } function fetchBazaarItems(itemName) { console.log('IronNerd Bazaar Enhancements: Fetching bazaar items for:', itemName); GM_xmlhttpRequest({ method: 'GET', url: `https://www.ironnerd.me/search_bazaar_items?item_name=${encodeURIComponent(itemName)}`, onload: function(response) { if (response.status === 200) { try { const data = JSON.parse(response.responseText); displayBazaarItems(data.bazaar_items, itemName); } catch (e) { displayErrorMessage('Error parsing server response.'); console.error('IronNerd Bazaar Enhancements: Parse Error:', e); } } else { displayErrorMessage('Error fetching bazaar items.'); console.error('IronNerd Bazaar Enhancements: Fetch Bazaar Items Error:', response.responseText); } }, onerror: function(error) { displayErrorMessage('Network error occurred. Please try again later.'); console.error('IronNerd Bazaar Enhancements: Network Error:', error); } }); } function displayBazaarItems(items, itemName = '') { console.log('IronNerd Bazaar Enhancements: displayBazaarItems - itemName:', itemName); let container = document.getElementById('bazaar-enhancer-container'); if (!container) { container = document.createElement('div'); container.id = 'bazaar-enhancer-container'; container.style.marginTop = '20px'; const delimiter = document.querySelector('.delimiter___zFh2E'); if (delimiter && delimiter.parentNode) { delimiter.parentNode.insertBefore(container, delimiter.nextSibling); } else { document.body.appendChild(container); } } container.innerHTML = ''; const title = document.createElement('h2'); title.textContent = `Bazaar Listings for "${itemName}"`; title.style.textAlign = 'center'; container.appendChild(title); if (items.length === 0) { const noItemsMessage = document.createElement('p'); noItemsMessage.textContent = 'No items found in registered bazaars.'; noItemsMessage.style.textAlign = 'center'; container.appendChild(noItemsMessage); return; } const tableWrapper = document.createElement('div'); tableWrapper.style.overflowX = 'auto'; tableWrapper.style.webkitOverflowScrolling = 'touch'; const table = document.createElement('table'); table.style.width = '100%'; table.style.borderCollapse = 'collapse'; table.style.minWidth = '600px'; const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); const headers = ['Image', 'Name', 'Owner', 'Price', 'Quantity', 'Visit Bazaar']; headers.forEach(header => { const th = document.createElement('th'); th.textContent = header; th.style.border = '1px solid #ccc'; th.style.padding = '6px'; th.style.backgroundColor = '#f2f2f2'; th.style.textAlign = 'center'; headerRow.appendChild(th); }); thead.appendChild(headerRow); table.appendChild(thead); const tbody = document.createElement('tbody'); items.forEach(itemData => { const item = itemData.item; const row = document.createElement('tr'); const imgCell = document.createElement('td'); imgCell.style.border = '1px solid #ccc'; imgCell.style.padding = '4px'; imgCell.style.textAlign = 'center'; const img = document.createElement('img'); img.src = `/images/items/${item.ID}/small.png`; img.alt = item.name; img.style.height = '30px'; imgCell.appendChild(img); row.appendChild(imgCell); const nameCell = document.createElement('td'); nameCell.innerText = item.name; nameCell.setAttribute('data-label', 'Name'); nameCell.style.border = '1px solid #ccc'; nameCell.style.padding = '8px'; nameCell.style.textAlign = 'center'; row.appendChild(nameCell); const ownerCell = document.createElement('td'); ownerCell.innerText = itemData.owner; ownerCell.setAttribute('data-label', 'Owner'); ownerCell.style.border = '1px solid #ccc'; ownerCell.style.padding = '8px'; ownerCell.style.textAlign = 'center'; const ownerLink = document.createElement('a'); ownerLink.href = `https://www.torn.com/profiles.php?XID=${itemData.user_id}`; ownerLink.textContent = itemData.owner; ownerLink.target = '_blank'; ownerLink.style.color = 'inherit'; ownerCell.appendChild(ownerLink); row.appendChild(ownerCell); const priceCell = document.createElement('td'); priceCell.innerText = `$${item.price.toLocaleString()}`; priceCell.setAttribute('data-label', 'Price ($)'); priceCell.style.border = '1px solid #ccc'; priceCell.style.padding = '8px'; priceCell.style.textAlign = 'center'; row.appendChild(priceCell); const quantityCell = document.createElement('td'); quantityCell.innerText = item.quantity; quantityCell.setAttribute('data-label', 'Quantity'); quantityCell.style.border = '1px solid #ccc'; quantityCell.style.padding = '8px'; quantityCell.style.textAlign = 'center'; row.appendChild(quantityCell); const bazaarCell = document.createElement('td'); bazaarCell.style.border = '1px solid #ccc'; bazaarCell.style.padding = '8px'; bazaarCell.style.textAlign = 'center'; const bazaarLink = document.createElement('a'); bazaarLink.href = `https://www.torn.com/bazaar.php?userID=${itemData.user_id}`; bazaarLink.textContent = 'Visit'; bazaarLink.target = '_blank'; bazaarLink.style.color = '#007bff'; bazaarLink.style.textDecoration = 'none'; bazaarLink.addEventListener('mouseover', () => { bazaarLink.style.textDecoration = 'underline'; }); bazaarLink.addEventListener('mouseout', () => { bazaarLink.style.textDecoration = 'none'; }); bazaarCell.appendChild(bazaarLink); bazaarCell.setAttribute('data-label', 'Visit Bazaar'); row.appendChild(bazaarCell); tbody.appendChild(row); }); table.appendChild(tbody); tableWrapper.appendChild(table); container.appendChild(tableWrapper); adjustOneDollarTableTheme(); } function isValidApiKey(apiKey) { const apiKeyPattern = /^[A-Za-z0-9]{16}$/; return apiKeyPattern.test(apiKey); } })();