LostCity Markets: Additional Functions

Hide listings from blocked sellers or items. Shift-click item icons to block them instantly on lostcity.markets pages.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         LostCity Markets: Additional Functions
// @namespace    http://tampermonkey.net/
// @version      3.4
// @description  Hide listings from blocked sellers or items. Shift-click item icons to block them instantly on lostcity.markets pages.
// @match        https://lostcity.markets/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const SELLER_KEY = 'blockedSellersList';
    const ITEM_KEY = 'blockedItemsList';

    function getList(key) {
        const stored = localStorage.getItem(key);
        return stored ? JSON.parse(stored) : [];
    }

    function saveList(key, list) {
        localStorage.setItem(key, JSON.stringify(list));
    }

    function normalizeName(name) {
        return name.trim().toLowerCase().replace(/\s+/g, ' ');
    }

    function hideListings() {
        const blockedSellers = getList(SELLER_KEY).map(normalizeName);
        const blockedItems = getList(ITEM_KEY).map(normalizeName);
        const rows = document.querySelectorAll('tr');

        rows.forEach(row => {
            const sellerLink = row.querySelector('a[href^="/users/"]');
            const itemImg = row.querySelector('img[alt$="Icon"]');

            const sellerName = sellerLink?.textContent.trim();
            const itemAlt = itemImg?.getAttribute('alt') || '';
            const itemName = itemAlt.replace(/ icon$/i, '').trim();

            const isBlockedSeller = sellerName && blockedSellers.includes(normalizeName(sellerName));
            const isBlockedItem = itemName && blockedItems.includes(normalizeName(itemName));

            row.style.display = (isBlockedSeller || isBlockedItem) ? 'none' : '';
        });
    }

    function createButton(label, onClick, offsetY) {
        const button = document.createElement('button');
        button.textContent = label;
        Object.assign(button.style, {
            position: 'fixed',
            top: `${offsetY}px`,
            left: '20px',
            zIndex: 10000,
            width: '160px',
            height: '40px',
            padding: '8px',
            backgroundColor: '#222',
            color: '#fff',
            border: 'none',
            borderRadius: '6px',
            cursor: 'pointer',
            fontSize: '14px',
            boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
            textAlign: 'center'
        });
        button.addEventListener('click', onClick);
        document.body.appendChild(button);
    }

    function addBlockUnblockButtons() {
        // Seller block
        createButton('🔕 Block Seller', () => {
            const name = prompt('Enter seller name to block:');
            if (name) {
                const list = getList(SELLER_KEY);
                const norm = normalizeName(name);
                if (!list.map(normalizeName).includes(norm)) {
                    list.push(name.trim());
                    saveList(SELLER_KEY, list);
                    hideListings();
                    alert(`Seller "${name}" has been blocked.`);
                } else {
                    alert(`Seller "${name}" is already blocked.`);
                }
            }
        }, 20);

        // Seller unblock
        createButton('✅ Unblock Seller', () => {
            const list = getList(SELLER_KEY);
            if (list.length === 0) return alert('Your seller block list is empty.');
            const name = prompt(`Blocked sellers:\n${list.join(', ')}\n\nEnter seller name to unblock:`);
            const norm = normalizeName(name);
            const updated = list.filter(s => normalizeName(s) !== norm);
            if (updated.length < list.length) {
                saveList(SELLER_KEY, updated);
                alert(`Seller "${name}" has been unblocked.`);
                location.reload();
            } else {
                alert(`Seller "${name}" is not in your block list.`);
            }
        }, 70);

        // Item block
        createButton('📦 Block Item', () => {
            const itemName = prompt('Enter item name to block (e.g., Runite Bar):');
            if (itemName) {
                const list = getList(ITEM_KEY);
                const norm = normalizeName(itemName);
                if (!list.map(normalizeName).includes(norm)) {
                    list.push(itemName.trim());
                    saveList(ITEM_KEY, list);
                    hideListings();
                    alert(`Item "${itemName}" has been blocked.`);
                } else {
                    alert(`Item "${itemName}" is already blocked.`);
                }
            }
        }, 120);

        // Item unblock
        createButton('📦 Unblock Item', () => {
            const list = getList(ITEM_KEY);
            if (list.length === 0) return alert('Your item block list is empty.');
            const itemName = prompt(`Blocked items:\n${list.join(', ')}\n\nEnter item name to unblock:`);
            const norm = normalizeName(itemName);
            const updated = list.filter(i => normalizeName(i) !== norm);
            if (updated.length < list.length) {
                saveList(ITEM_KEY, updated);
                alert(`Item "${itemName}" has been unblocked.`);
                location.reload();
            } else {
                alert(`Item "${itemName}" is not in your block list.`);
            }
        }, 170);
    }

    function enableShiftClickBlocking() {
        document.addEventListener('click', e => {
            if (e.shiftKey && e.target.tagName === 'IMG' && e.target.alt.endsWith('Icon')) {
                const itemName = e.target.alt.replace(/ icon$/i, '').trim();
                const norm = normalizeName(itemName);
                const list = getList(ITEM_KEY);
                if (!list.map(normalizeName).includes(norm)) {
                    list.push(itemName);
                    saveList(ITEM_KEY, list);
                    hideListings();
                    alert(`Item "${itemName}" has been blocked via Shift+Click.`);
                } else {
                    alert(`Item "${itemName}" is already blocked.`);
                }
                e.preventDefault();
                e.stopPropagation();
            }
        }, true);
    }

    function addInstructionLabel() {
    const label = document.createElement('div');
    label.textContent = '💡 Shift-click an item icon to add it to your block list.';
    Object.assign(label.style, {
        position: 'fixed',
        top: '220px',
        left: '20px',
        zIndex: 10000,
        width: '260px',
        padding: '10px',
        backgroundColor: '#222',
        color: '#fff',
        border: 'none',
        borderRadius: '6px',
        fontSize: '13px',
        fontFamily: 'sans-serif',
        boxShadow: '0 2px 6px rgba(0,0,0,0.3)',
        textAlign: 'center'
    });
    document.body.appendChild(label);
}


    // Initialize
    hideListings();
    addBlockUnblockButtons();
    enableShiftClickBlocking();
    addInstructionLabel();

    const observer = new MutationObserver(hideListings);
    observer.observe(document.body, { childList: true, subtree: true });
})();