Greasy Fork is available in English.

Closet Item Remover

Helps you remove items from your closet.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

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