Helps you remove items from your closet.
// ==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()
}
}
})();