Created
January 13, 2026 16:17
-
-
Save OJ7/4bf7084a1e8e3cae8d68b8a3f1ab9c0d to your computer and use it in GitHub Desktop.
Sort all listings by price on Swappa (instead of "featured" first)
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 Sort all listings by price on Swappa (instead of "featured" first) | |
| // @namespace Violentmonkey Scripts | |
| // @match https://swappa.com/listings/* | |
| // @grant none | |
| // @version 1.0 | |
| // @author - | |
| // @description 1/13/2026, 10:30:33 AM | |
| // ==/UserScript== | |
| // Disclaimer: AI-generated script | |
| // Sort table rows by price only (ignoring featured/non-featured status) | |
| function sortTableByPrice() { | |
| // Get the table and tbody | |
| const table = document.getElementById("listings_table"); | |
| if (!table) { | |
| console.error('Table with id "listings_table" not found'); | |
| return; | |
| } | |
| const tbody = table.querySelector("tbody"); | |
| if (!tbody) { | |
| console.error("Table tbody not found"); | |
| return; | |
| } | |
| // Get all rows from tbody | |
| const rows = Array.from(tbody.querySelectorAll("tr")); | |
| // Extract price from each row and create sortable array | |
| const rowsWithPrices = rows.map((row, index) => { | |
| // Find the price span element | |
| const priceSpan = row.querySelector('span[itemprop="price"]'); | |
| if (!priceSpan) { | |
| console.warn(`Row ${index + 1} does not have a price span`); | |
| return { row, price: Infinity }; // Put rows without prices at the end | |
| } | |
| // Extract price as number | |
| const priceText = priceSpan.textContent.trim(); | |
| const price = parseFloat(priceText); | |
| if (isNaN(price)) { | |
| console.warn(`Row ${index + 1} has invalid price: "${priceText}"`); | |
| return { row, price: Infinity }; | |
| } | |
| return { row, price }; | |
| }); | |
| // Sort by price (ascending order) | |
| rowsWithPrices.sort((a, b) => { | |
| return a.price - b.price; | |
| }); | |
| // Clear tbody | |
| tbody.innerHTML = ""; | |
| // Re-insert rows in sorted order and update row numbers | |
| rowsWithPrices.forEach((item, index) => { | |
| const row = item.row; | |
| // Update row number in the first td | |
| const firstTd = row.querySelector("td:first-child"); | |
| if (firstTd) { | |
| // Find the text node that contains the number | |
| const metaTag = firstTd.querySelector("meta"); | |
| const textNodes = Array.from(firstTd.childNodes).filter( | |
| (node) => node.nodeType === Node.TEXT_NODE | |
| ); | |
| if (textNodes.length > 0) { | |
| // Update the first text node (which should contain the number) | |
| const numberTextNode = textNodes[0]; | |
| // Preserve the whitespace formatting | |
| const whitespaceMatch = | |
| numberTextNode.textContent.match(/^(\s*)\d+(\s*)$/); | |
| if (whitespaceMatch) { | |
| numberTextNode.textContent = | |
| whitespaceMatch[1] + (index + 1) + whitespaceMatch[2]; | |
| } else { | |
| numberTextNode.textContent = `\n ${ | |
| index + 1 | |
| }\n `; | |
| } | |
| } else if (metaTag) { | |
| // If no text node exists, create one before the meta tag | |
| const newTextNode = document.createTextNode( | |
| `\n ${index + 1}\n ` | |
| ); | |
| firstTd.insertBefore(newTextNode, metaTag); | |
| } else { | |
| // Fallback: just set text content | |
| firstTd.textContent = index + 1; | |
| } | |
| } | |
| // Append row to tbody | |
| tbody.appendChild(row); | |
| }); | |
| console.log(`Sorted ${rowsWithPrices.length} rows by price`); | |
| } | |
| sortTableByPrice(); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment