Last active
December 12, 2025 08:35
-
-
Save occluder/61d8bba347b61092d7c21d2739f23761 to your computer and use it in GitHub Desktop.
Warframe.Market Order Bump Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Warframe.Market Order Bump | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.7 | |
| // @description Bump all your warframe.market orders with a button. As of 10-12-2025 this no longer works | |
| // @author occluder | |
| // @match https://warframe.market/profile/* | |
| // @connect api.warframe.market | |
| // @connect warframe.market | |
| // @grant GM.xmlHttpRequest | |
| // @grant GM_log | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| // SET USERNAME FOR SCRIPT TO WORK | |
| const USERNAME = null; | |
| const ORDER_API_BASE = 'https://api.warframe.market/v1/profile/'; | |
| const CSRF_META_SELECTOR = 'meta[name="csrf-token"]'; | |
| if (!USERNAME) { | |
| alert('[WFM Order Bump] Please set your username in the script.'); | |
| return; | |
| } | |
| // Track if button has been added to avoid duplicates | |
| let buttonAdded = false; | |
| function log(...args) { | |
| console.log('[WFM Order Bump]', ...args); | |
| if (typeof GM_log !== 'undefined') GM_log(args.join(' ')); | |
| } | |
| function isUserProfile() { | |
| return USERNAME === window.location.pathname.split('/').pop(); | |
| } | |
| function getCSRFToken() { | |
| const meta = document.querySelector(CSRF_META_SELECTOR); | |
| if (meta && meta.content) { | |
| log('Found CSRF token'); | |
| return meta.content; | |
| } | |
| log('CSRF token not found in meta tag'); | |
| return null; | |
| } | |
| function fetchWithGM(url, method, headers, body) { | |
| return new Promise((resolve) => { | |
| GM.xmlHttpRequest({ | |
| method: method, | |
| url: url, | |
| headers: headers, | |
| data: body, | |
| credentials: true, | |
| onload: function (response) { | |
| resolve({ | |
| status: response.status, | |
| responseText: response.responseText, | |
| ok: response.status >= 200 && response.status < 300 | |
| }); | |
| }, | |
| onerror: function (response) { | |
| resolve({ | |
| status: response.status, | |
| responseText: response.responseText || 'Network error', | |
| ok: false | |
| }); | |
| } | |
| }); | |
| }); | |
| } | |
| async function fetchOrders() { | |
| const url = ORDER_API_BASE + USERNAME + '/orders'; | |
| log('Fetching orders from API'); | |
| const response = await fetchWithGM(url, 'GET', { | |
| 'Referer': 'https://warframe.market/', | |
| 'Origin': 'https://warframe.market' | |
| }, null); | |
| if (!response.ok) { | |
| throw new Error(`API request failed: ${response.status}`); | |
| } | |
| const data = JSON.parse(response.responseText); | |
| const sellOrders = data?.payload?.sell_orders || []; | |
| const buyOrders = data?.payload?.buy_orders || []; | |
| log(`Found ${sellOrders.length} sell orders and ${buyOrders.length} buy orders from API`); | |
| return [...sellOrders, ...buyOrders]; | |
| } | |
| function extractOrders(apiData) { | |
| const orders = []; | |
| apiData.forEach(order => { | |
| if (order.id && order.platinum !== undefined && order.quantity !== undefined && order.visible !== undefined) { | |
| orders.push({ | |
| id: order.id, | |
| platinum: order.platinum, | |
| quantity: order.quantity, | |
| visible: order.visible | |
| }); | |
| } | |
| }); | |
| log(`Extracted ${orders.length} valid orders`); | |
| return orders; | |
| } | |
| function createButton() { | |
| const button = document.createElement('button'); | |
| button.className = 'btn btn__primary--L8HyD'; | |
| button.type = 'button'; | |
| button.tabIndex = 0; | |
| button.setAttribute('data-order-bump', 'true'); // Mark our button | |
| const innerDiv = document.createElement('div'); | |
| const svg = ` | |
| <svg class="wfm-icon" viewBox="0 0 24 24" width="16" height="16"> | |
| <path fill="currentColor" d="M17 3a2.8 2.8 0 0 1 4 4L8 20l-5 2 2-5Z"></path> | |
| </svg>`; | |
| innerDiv.innerHTML = `${svg}<span>Bump Orders</span>`; | |
| button.appendChild(innerDiv); | |
| return button; | |
| } | |
| async function updateOrder(order, csrfToken) { | |
| const url = 'https://api.warframe.market/v2/order/' + encodeURIComponent(order.id); | |
| const body = JSON.stringify({ | |
| platinum: order.platinum, | |
| quantity: order.quantity, | |
| visible: order.visible | |
| }); | |
| const headers = { | |
| 'Content-Type': 'application/json', | |
| 'Referer': 'https://warframe.market/', | |
| 'Origin': 'https://warframe.market', | |
| 'X-CSRF-Token': csrfToken | |
| }; | |
| const response = await fetchWithGM(url, 'PATCH', headers, body); | |
| if (response.ok) { | |
| return { success: true, id: order.id }; | |
| } else { | |
| const error = `HTTP ${response.status}: ${response.responseText.substring(0, 100)}`; | |
| return { success: false, id: order.id, error }; | |
| } | |
| } | |
| async function handleButtonClick(event) { | |
| log('Starting bump process'); | |
| const csrfToken = getCSRFToken(); | |
| if (!csrfToken) { | |
| alert('CSRF token not found. Are you logged in?'); | |
| return; | |
| } | |
| let ordersData; | |
| try { | |
| ordersData = await fetchOrders(); | |
| } catch (error) { | |
| alert('Failed to fetch orders from API: ' + error.message); | |
| return; | |
| } | |
| const orders = extractOrders(ordersData); | |
| if (orders.length === 0) { | |
| alert('No valid orders found to bump'); | |
| return; | |
| } | |
| const button = event.target.closest('button[data-order-bump]'); | |
| const originalText = button.textContent; | |
| button.disabled = true; | |
| button.textContent = 'Bumping orders...'; | |
| const failed = []; | |
| for (const order of orders) { | |
| const result = await updateOrder(order, csrfToken); | |
| if (!result.success) { | |
| failed.push(result); | |
| } | |
| await new Promise(resolve => setTimeout(resolve, 750)); | |
| } | |
| button.disabled = false; | |
| button.textContent = originalText; | |
| if (failed.length > 0) { | |
| const errorMsg = failed.map(f => `Order ${f.id}: ${f.error}`).join('\n'); | |
| alert(`Some orders failed to update:\n\n${errorMsg}`); | |
| } else { | |
| alert(`Successfully bumped ${orders.length} orders`); | |
| } | |
| } | |
| function addButton() { | |
| if (!isUserProfile()) { | |
| return; // Not on the correct profile page | |
| } | |
| if (document.querySelector('button[data-order-bump]')) { | |
| return; | |
| } | |
| const targetContainer = document.querySelector('.description__buttons'); | |
| if (!targetContainer) { | |
| log('Could not find button container'); | |
| return; | |
| } | |
| const button = createButton(); | |
| button.addEventListener('click', handleButtonClick); | |
| targetContainer.appendChild(button); | |
| buttonAdded = true; | |
| log('Button added to UI'); | |
| } | |
| function setupNavigationObserver() { | |
| let currentUrl = window.location.href; | |
| const observer = new MutationObserver(() => { | |
| if (window.location.href !== currentUrl) { | |
| currentUrl = window.location.href; | |
| log('URL changed to:', currentUrl); | |
| if (!isUserProfile()) { | |
| buttonAdded = false; | |
| } | |
| setTimeout(addButton, 500); | |
| } | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| window.addEventListener('popstate', () => { | |
| setTimeout(addButton, 500); | |
| }); | |
| } | |
| function setupDOMObserver() { | |
| const observer = new MutationObserver((mutations) => { | |
| for (const mutation of mutations) { | |
| for (const node of mutation.addedNodes) { | |
| // Check if the added node contains our target container | |
| if (node.nodeType === 1) { // Element node | |
| if (node.querySelector && node.querySelector('.description__buttons')) { | |
| addButton(); | |
| } else if (node.classList && node.classList.contains('description__buttons')) { | |
| addButton(); | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| } | |
| function main() { | |
| if (!isUserProfile()) { | |
| log('Not on user profile page, skipping'); | |
| return; | |
| } | |
| log('Script initialized for user:', USERNAME); | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', () => { | |
| addButton(); | |
| setupNavigationObserver(); | |
| setupDOMObserver(); | |
| }); | |
| } else { | |
| addButton(); | |
| setupNavigationObserver(); | |
| setupDOMObserver(); | |
| } | |
| } | |
| main(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment