Closet Item Remover

Helps you remove items from your closet.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Closet Item Remover
// @namespace    Nyu@Clraik
// @version      1.0.0
// @description  Helps you remove items from your closet.
// @author       Nyu
// @match        *://*.neopets.com/closet.phtml*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=neopets.com
// @license      MIT
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM.getValue
// @grant        GM.setValue
// ==/UserScript==

(async function() {
    'use strict';

    if (typeof GM_getValue == "undefined") GM_getValue = GM.getValue
    if (typeof GM_setValue == "undefined") GM_setValue = GM.setValue

    const sleep = ms => new Promise(r => setTimeout(r, ms))
    const randWait = () => sleep(3000 + Math.random() * 2000)

    const PREFIX = 'cir.'
    const get = key => GM_getValue(PREFIX + key)
    const set = (key, val) => GM_setValue(PREFIX + key, val)

    const container = document.createElement('div')
    container.style.display = 'flex'
    container.style.alignItems = 'center'
    container.style.justifyContent = 'center'
    container.style.gap = '16px'
    container.style.padding = '12px 20px'
    container.style.margin = '10px auto'
    container.style.background = '#efefc3'
    container.style.border = '2px solid #c5c587'
    container.style.borderRadius = '8px'
    container.style.maxWidth = '500px'
    container.style.flexWrap = 'wrap'

    const makeCheckbox = (label, id, checked) => {
        const wrapper = document.createElement('label')
        wrapper.style.display = 'flex'
        wrapper.style.alignItems = 'center'
        wrapper.style.gap = '4px'
        wrapper.style.cursor = 'pointer'
        wrapper.style.fontWeight = 'bold'
        wrapper.style.fontSize = '14px'
        const cb = document.createElement('input')
        cb.type = 'checkbox'
        cb.id = id
        cb.checked = checked
        cb.style.cursor = 'pointer'
        wrapper.append(cb, label)
        return wrapper
    }

    const savedNp = await get('np')
    const savedNc = await get('nc')
    const npCheck = makeCheckbox('NP Items', 'cir-np', savedNp ?? true)
    const ncCheck = makeCheckbox('NC Items', 'cir-nc', savedNc ?? false)
    npCheck.querySelector('input').addEventListener('change', e => set('np', e.target.checked))
    ncCheck.querySelector('input').addEventListener('change', e => set('nc', e.target.checked))
    container.append(npCheck, ncCheck)

    const pinExists = document.getElementById('pin_field')
    if (pinExists) {
        const pinWrapper = document.createElement('label')
        pinWrapper.style.display = 'flex'
        pinWrapper.style.alignItems = 'center'
        pinWrapper.style.gap = '4px'
        pinWrapper.style.fontWeight = 'bold'
        pinWrapper.style.fontSize = '14px'
        const pinInput = document.createElement('input')
        pinInput.type = 'text'
        pinInput.id = 'cir-pin'
        pinInput.maxLength = 4
        pinInput.placeholder = '0000'
        pinInput.value = await get('pin') ?? ''
        pinInput.style.width = '50px'
        pinInput.style.padding = '4px 6px'
        pinInput.style.borderRadius = '4px'
        pinInput.style.border = '1px solid #c5c587'
        pinInput.style.textAlign = 'center'
        pinInput.style.fontSize = '14px'
        pinInput.addEventListener('input', e => set('pin', e.target.value))
        pinWrapper.append('PIN ', pinInput)
        container.append(pinWrapper)
    }

    const running = await get('running') ?? false
    const button = document.createElement('button')
    button.className = 'button-default__2020'
    button.style.cursor = 'pointer'

    const setRunning = (state) => {
        set('running', state)
        button.textContent = state ? 'Stop' : 'Remove Items'
        button.classList.toggle('button-yellow__2020', !state)
        button.classList.toggle('button-red__2020', state)
    }
    setRunning(running)

    button.onclick = async () => {
        if (await get('running')) { setRunning(false); return }
        setRunning(true)
        set('nextPage', currentPage)
        fillAndSubmit()
    }

    container.append(button)

    const quickStockForm = document.querySelector('form[action="process_closet.phtml"]')
    if (quickStockForm) {
        quickStockForm.parentNode.insertBefore(container, quickStockForm)
    }

    const pageSelect = document.querySelector('select[name="page"]')
    const currentPage = pageSelect ? parseInt(pageSelect.value) : 1
    const lastPage = pageSelect ? parseInt(pageSelect.options[pageSelect.options.length - 1].value) : 1

    const goToPage = (page) => {
        const url = new URL(window.location.href)
        url.searchParams.set('page', page)
        window.location.href = url.toString()
    }

    const fillAndSubmit = () => {
        const doNp = document.getElementById('cir-np').checked
        const doNc = document.getElementById('cir-nc').checked
        const rows = quickStockForm.querySelectorAll('tr[bgcolor]')
        let filled = false
        for (const row of rows) {
            const isNc = row.textContent.includes('(Artifact -')
            if ((isNc && !doNc) || (!isNc && !doNp)) continue
            const tds = row.querySelectorAll('td')
            const qty = tds[4]?.querySelector('b')?.textContent?.trim()
            const input = tds[5]?.querySelector('input[type="text"]')
            if (qty && input) { input.value = qty; filled = true }
        }
        if (!filled) {
            if (currentPage >= lastPage) setRunning(false)
            else { set('nextPage', currentPage + 1); goToPage(currentPage + 1) }
            return
        }
        const pinField = document.getElementById('pin_field')
        if (pinField) {
            const savedPin = document.getElementById('cir-pin')?.value
            if (!savedPin) { setRunning(false); alert('PIN is required but not set.'); return }
            pinField.value = savedPin
        }
        if (currentPage >= lastPage) set('running', false)
        else set('nextPage', currentPage + 1)
        quickStockForm.querySelector('input[type="submit"]').click()
    }

    if (running && quickStockForm) {
        await randWait()
        const targetPage = await get('nextPage') ?? 1
        if (currentPage !== targetPage) {
            goToPage(targetPage)
        } else {
            fillAndSubmit()
        }
    }
})();