Closet Item Remover

Helps you remove items from your closet.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==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()
        }
    }
})();