├── questlogbutton.user.js
├── fcbetcount.user.js
├── petpetpuddle.user.js
├── dtistickyheader.user.js
├── scratchcard.user.js
├── wishingwell.user.js
├── expandslider.user.js
├── neoboardlinks.user.js
├── inventorydivider.user.js
├── stockmarket.user.js
├── training.user.js
├── nfclinks.user.js
├── lunartemple.user.js
├── rememberzap.user.js
├── galleryquickcat.user.js
├── jnsdbhelper.user.js
├── braintreehelper.user.js
├── snowager.user.js
├── obelisk.user.js
├── shopwizard.user.js
├── lostandpoundfilter.user.js
├── compactquestlog.user.js
├── plotvoidessence.user.js
├── questloglinks.user.js
├── stampscollected.user.js
├── README.md
├── booksread.user.js
└── lastswprice.user.js
/questlogbutton.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - rightclick-able Quest Log button
3 | // @version 2024-02-15
4 | // @description Adds an anchor for links that cannot be middle/right clicked
5 | // @author senerio
6 | // @match *://*.neopets.com/*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | $('.nav-quest-icon__2020').append('')
12 |
--------------------------------------------------------------------------------
/fcbetcount.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Food Club bet count
3 | // @version 2024-01-24
4 | // @description Quickly confirm that 10 bets have been made
5 | // @author senerio
6 | // @match *://*.neopets.com/pirates/foodclub.phtml?type=current_bets
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | const count = $('.content table tr[bgcolor=white]').length - 1;
12 | $('.content table tr[bgcolor=darkred] b').text(`Current Bets (${count})`);
13 |
--------------------------------------------------------------------------------
/petpetpuddle.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Petpet Puddle and Lab Ray
3 | // @version 2024-07-22
4 | // @description Fix page display with many petpets
5 | // @author senerio
6 | // @match *://*.neopets.com/pool/puddle.phtml
7 | // @match *://*.neopets.com/petpetlab.phtml
8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
9 | // @grant none
10 | // ==/UserScript==
11 |
12 | $('.content table').wrap('
'); // horizontal scroll
13 | $('.content table td').css({'display': 'inline-block'}); // expand
14 |
--------------------------------------------------------------------------------
/dtistickyheader.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - DTI closet sticky header
3 | // @description On a user's DTI closet, keep the section header visible while scrolling.
4 | // @version 2024-01-15
5 | // @author senerio
6 | // @match https://impress.openneo.net/user/*/closet
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant GM_addStyle
9 | // ==/UserScript==
10 |
11 | GM_addStyle(`.closet-hangers-group header {
12 | position: sticky !important;
13 | top: 0;
14 | z-index: 1;
15 | background-color: rgba(255,255,255,0.75);
16 | }
17 |
18 | .closet-list header {
19 | top: 3em;
20 | }`);
21 |
--------------------------------------------------------------------------------
/scratchcard.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Scratchcards
3 | // @version 2024-02-18
4 | // @description Adds link back to kiosk, auto selects card from the dropdown
5 | // @author senerio
6 | // @match *://*.neopets.com/winter/kiosk*.phtml*
7 | // @match *://*.neopets.com/halloween/scratch*.phtml*
8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
9 | // @grant none
10 | // ==/UserScript==
11 |
12 | const path = window.location.pathname;
13 | if(path.includes('2')) {
14 | $('.content form input').before(`Scratch again
`);
15 | }
16 | else {
17 | $('select[name=card_id] option').eq(1).prop('selected', true);
18 | }
19 |
--------------------------------------------------------------------------------
/wishingwell.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Wishing Well autofill
3 | // @version 2024-08-11
4 | // @description Autofill donation amount and item name; no autofill if 7 wishes are done
5 | // @author senerio, Monfo
6 | // @match *://*.neopets.com/wishing.phtml*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | // Change the "item" variable to whichever item you'd like to wish for
12 | const item = 'Snowager Stamp';
13 |
14 | if ((!window.location.search && document.querySelector('.content').children[8].children.length === 1) || (window.location.search && document.querySelector('.content').children.length === 13)) {
15 | $('input[name=donation]').val('21');
16 | $('input[name=wish]').val(item);
17 | };
18 |
--------------------------------------------------------------------------------
/expandslider.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Expand Slider
3 | // @version 2024-05-02
4 | // @description Remove scrolling, view all results at once
5 | // @author senerio
6 | // @match *://*.neopets.com/freebies/*
7 | // @match *://*.neopets.com/lab2.phtml
8 | // @match *://*.neopets.com/worlds/roo/merrygoround.phtml
9 | // @match *://*.neopets.com/pound/transfer.phtml
10 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
11 | // @grant GM_addStyle
12 | // ==/UserScript==
13 |
14 | GM_addStyle(`#bxlist {
15 | width: auto !important;
16 | transform: none !important;
17 | }
18 | .bx-viewport {
19 | overflow: auto !important;
20 | height: auto !important;
21 | }
22 | .bx-clone, .bx-controls {
23 | display: none;
24 | }
25 | br:has(+input) {
26 | line-height: 0.25em;
27 | }`);
28 |
--------------------------------------------------------------------------------
/neoboardlinks.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Neoboards links
3 | // @version 2024-06-02
4 | // @description Adds clickable link to unanchored site URLs
5 | // @author senerio
6 | // @match *://*.neopets.com/neoboards/topic.phtml?topic=*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | function attachLink(regex, e) {
12 | const url = $(e).text().match(regex);
13 | const urlEncoded = $('').text(url).html();
14 | const newHtml = $(e).html().replace(urlEncoded, `${urlEncoded}`);
15 | $(e).html(newHtml);
16 | }
17 |
18 | $('.boardPostMessage:contains("openneo.net")').each(function(e) { attachLink(/(impress(-2020)?\.openneo\.net\/[\w\/\-_?=&;~\.]*)/g, this) })
19 | $('.boardPostMessage:contains("neopets.com")').each(function(e) { attachLink(/((www\.)?neopets\.com\/[\w\/\-_?=&;~\.]*)/g, this) })
20 |
--------------------------------------------------------------------------------
/inventorydivider.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Inventory Divider
3 | // @version 2024-06-02
4 | // @description Separate auctioned/trading items in your inventory
5 | // @author senerio
6 | // @match *://*.neopets.com/inventory.phtml
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | function separateActiveItems() {
12 | const activeItems = $( ['auctioned', 'trading'].map(i => { return `.item-subname:contains("${i}"):visible` }).join(',') );
13 | const itemGrid = $('.item-grid:visible');
14 | if(activeItems.length && (itemGrid.children().length - activeItems.length)) {
15 | itemGrid.after('
');
16 | activeItems.each((i,e) => { $(e).parent().appendTo($('.activeItemsContainer:visible')) });
17 | }
18 | }
19 |
20 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
21 | if(settings.url.includes('inventory.php')) {
22 | separateActiveItems();
23 | }
24 | });
25 |
--------------------------------------------------------------------------------
/stockmarket.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Stock Market autofill
3 | // @version 2024-02-17
4 | // @description Picks any stock at the cheapest price
5 | // @author senerio
6 | // @match *://*.neopets.com/stockmarket.phtml?type=buy
7 | // @match *://*.neopets.com/stockmarket.phtml?*type=list*
8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
9 | // @grant none
10 | // ==/UserScript==
11 |
12 | if(window.location.search.includes('buy')) {
13 | $('input[name=amount_shares]').val('1000');
14 | $('input[name=ticker_symbol]').val(localStorage?.getItem('np_ticker'));
15 | }
16 |
17 | if(window.location.search.includes('list')) {
18 | const price = $('.perkBar').length ? 10 : 15;
19 | const ticker = $(`.content table tr td:nth-child(6):contains(${price})`).eq(-1).parent().find('td:nth-child(2)').text() || 'none';
20 | $('.content table').before(`${ticker} selected
`);
21 | localStorage?.setItem('np_ticker', ticker);
22 | }
23 |
24 | // document.querySelectorAll('.content table tr').forEach(i => { if(i.children[5].innerText == targetPrice) { ticker.push(i.children[1].innerText.match('.{4}')[0]) } });
25 |
--------------------------------------------------------------------------------
/training.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Training
3 | // @version 2024-05-09
4 | // @description Skips the main page and redirect to status page; begin training from the status page
5 | // @author senerio
6 | // @match *://*.neopets.com/island/training.phtml*
7 | // @match *://*.neopets.com/pirates/academy.phtml*
8 | // @match *://*.neopets.com/island/fight_training.phtml*
9 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
10 | // @grant none
11 | // ==/UserScript==
12 |
13 | if(!location.search.length) {
14 | location.replace(location.pathname + '?type=status');
15 | }
16 | else if(location.search.includes('status')) {
17 | const course = ['Level', 'Strength', 'Defence', 'Agility', 'Endurance'];
18 | const pet = $('.content table tr:nth-child(2n+1) td:only-child b').map((i,v) => v.innerText.split(' ')[0] ).toArray();
19 | $('.content table tr:nth-child(2n) td:first-child b').each((i,v) => {
20 | const path = location.pathname.split('/').pop();
21 | $(v).after(` +`);
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/nfclinks.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - NeoFood.Club Quick Links
3 | // @version 2024-06-27
4 | // @description Add bank and fc links to NFC pages. Also hides other edit buttons.
5 | // @author senerio
6 | // @match https://neofood.club/*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | setTimeout(function() {
12 | const style = 'padding-left: 2em; color: #fbb900; font-size: smaller; font-weight: bolder;'
13 | const nodeNew = Object.assign(document.createElement('div'), {innerHTML: `
14 | CHECK MAX BET
15 | BANK
16 | COLLECT
17 | CURRENT BETS
18 | `});
19 | const nodeRef = document.getElementsByTagName('header')[0].nextSibling.children[0];
20 | nodeRef.children[0].remove();
21 | nodeRef.append(nodeNew);
22 | }, 500);
--------------------------------------------------------------------------------
/lunartemple.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Lunar Temple
3 | // @version 2024-12-02
4 | // @description Highlights the correct answer for Shenkuu Lunar Temple
5 | // @author senerio
6 | // @match *://*.neopets.com/shenkuu/lunar/?show=puzzle
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | const choices = document.querySelectorAll('.content form td');
12 | if(!!choices.length) {
13 | let phase = Math.round( document.querySelector('.content div[style="width: 635px;"] script+script').innerHTML.match(/angleKreludor=(\d+)/)[1] / 22.5 );
14 | if ( [16, 8, 9,10,11,12,13,14,15].includes(phase)) { phase -= 8; }
15 | else if ([0, 1, 2, 3, 4, 5, 6, 7].includes(phase)) { phase += 8; }
16 | choices[phase].setAttribute('style', 'background-color: rgb(255, 203, 0);');
17 | }
18 |
19 | // Manual console copy-paste version
20 | // let phase = Math.round( document.querySelector('.content div script+script').innerHTML.match(/angleKreludor=(\d+)/)[1] / 22.5 ); if ([16, 8, 9,10,11,12,13,14,15].includes(phase)) { phase -= 8; } else if ([0, 1, 2, 3, 4, 5, 6, 7].includes(phase)) { phase += 8; } document.querySelector(`.content form input[name=phase_choice][value="${phase}"]`).parentElement.setAttribute('style', 'background-color: rgb(255, 203, 0);');
21 |
--------------------------------------------------------------------------------
/rememberzap.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Remember last zap
3 | // @version 2024-04-15
4 | // @description Remember last choice; auto redirect to zap selection page
5 | // @author senerio
6 | // @match *://*.neopets.com/petpetlab.phtml
7 | // @match *://*.neopets.com/lab2.phtml
8 | // @match *://*.neopets.com/lab.phtml
9 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
10 | // @grant none
11 | // ==/UserScript==
12 |
13 | function load() {
14 | const savedName = localStorage?.getItem('np_'+loc);
15 | document.querySelector(`.content form :not([aria-hidden=true])>*>input[value=${savedName}]`)?.click();
16 | document.querySelectorAll('.content form :not([aria-hidden=true]) input[type=radio][name=chosen]')
17 | .forEach(e => e.addEventListener('click', (event) => {
18 | localStorage?.setItem('np_'+loc, event.target.value);
19 | }));
20 | }
21 |
22 | const loc = location.pathname.split(/\/|\./).at(-2);
23 |
24 | if(loc=='lab') {
25 | location.replace('lab2.phtml');
26 | }
27 | else if(loc=='petpetlab') {
28 | load();
29 | }
30 | else if(loc=='lab2') {
31 | const observer = new MutationObserver(() => {
32 | load();
33 | observer.disconnect();
34 | });
35 | observer.observe(document.querySelector('#bxlist'), {childList: true});
36 | }
37 |
--------------------------------------------------------------------------------
/galleryquickcat.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Gallery quickcat
3 | // @version 2024-02-11
4 | // @description For easier management of uncategorized gallery items
5 | // @author senerio
6 | // @match *://*.neopets.com/gallery/quickcat.phtml?set_to_cat=*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | function hideCategorized() {
12 | const rows = $('form[name=quickcat_form] table tr[bgcolor] td:last-child:not(:contains("0"))')
13 | const isHidden = rows.eq(0).parent().prop('style').display == 'none'
14 | rows.each((i,e) => {
15 | $(e).parent().attr('style', `display: ${isHidden ? 'table-row' : 'none'};`)
16 | })
17 | }
18 | function selectUncategorized() {
19 | const rows = $('form[name=quickcat_form] table tr[bgcolor] td:last-child:contains("0")')
20 | const isChecked = rows.eq(0).parent().find('input').prop('checked')
21 | rows.each((i,e) => {
22 | $(e).parent().find('input').prop('checked', !isChecked)
23 | })
24 | }
25 |
26 | const format = ' ▶ text'
27 | $('form[name=quickcat_form]').before($(format.replace('text', 'hide all categorized')).click(hideCategorized))
28 | $('form[name=quickcat_form]').before($(format.replace('text', 'check all uncategorized')).click(selectUncategorized))
29 |
--------------------------------------------------------------------------------
/jnsdbhelper.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Helper for JN SDB Price Checker
3 | // @version 2024-10-01
4 | // @description Copy and paste once instead of 100+ times for Jellyneo's SDB price checker tool
5 | // @author senerio
6 | // @match *://*.neopets.com/safetydeposit.phtml*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | // local storage
12 | const sdbStorage = {
13 | 'key': 'np_sdb',
14 | 'get': function() {
15 | const items = JSON.parse(localStorage?.getItem(this.key)) || [];
16 | return items;
17 | },
18 | 'push': function(newItems) {
19 | const items = sdbStorage.get();
20 | localStorage?.setItem(this.key, JSON.stringify([...new Set([...items, ...newItems])]));
21 | },
22 | 'delete': function() {
23 | localStorage?.removeItem(this.key);
24 | }
25 | }
26 |
27 | // save items on page
28 | const ids = [];
29 | $('.remove_safety_deposit').each((i,v) => {
30 | const id = $(v).attr('name').match(/back_to_inv\[(.*)\]/)[1];
31 | ids.push(id);
32 | })
33 | sdbStorage.push(ids);
34 |
35 | // controls
36 | const listHtml = sdbStorage.get().map(v => ``).join('\n')
37 | $('.content').append(`
38 |
39 | 🡲 https://items.jellyneo.net/tools/sdb-price-checker/
40 |
`).append( $('🡲 clear SDB list?').click(() => { sdbStorage.delete() }) )
41 |
42 | // move to next page
43 | //$('.content .pointer:contains("»")').eq(0).click()
44 |
--------------------------------------------------------------------------------
/braintreehelper.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Brain Tree Helper
3 | // @version 2024-05-21
4 | // @description Saves Brain Tree answers from The Esophagor. Adds link back to Brain Tree.
5 | // @author senerio
6 | // @match *://*.neopets.com/halloween/braintree.phtml
7 | // @match *://*.neopets.com/halloween/esophagor.phtml*
8 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
9 | // @grant none
10 | // ==/UserScript==
11 |
12 | if(location.pathname.includes('braintree')) {
13 | if(document.querySelector('.brain-form')) {
14 | // autofill saved answer
15 | const answer = localStorage.getItem('np_braintree')?.split(',') || ['', ''];
16 | $('#answer_1').val(answer[0]);
17 | $('#answer_2').val(answer[1]);
18 | }
19 | else {
20 | // clear on new quest
21 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
22 | if(settings.data == "type=accept") {
23 | localStorage.removeItem('np_braintree');
24 | }
25 | })
26 | }
27 | $('#braintree_container').after('Go to The Esophagor
');
28 | }
29 | else if(location.pathname.includes('esophagor')) {
30 | $(document).on('ajaxSuccess', () => {
31 | const answer = document.querySelector('.quest_dialogue__2021 b u');
32 | if(answer) {
33 | // save answer
34 | localStorage.setItem('np_braintree', [ localStorage.getItem('np_braintree') , answer.innerText ].filter(Boolean).join(',') );
35 | // link to brain tree
36 | const brainTreeText = $('#esophagor-container p:contains("Brain Tree")')[0];
37 | brainTreeText.innerHTML = brainTreeText.innerHTML.replace('Brain Tree', 'Brain Tree');
38 | }
39 | })
40 | }
41 |
--------------------------------------------------------------------------------
/snowager.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Snowager stats and quick links
3 | // @version 2024-03-31
4 | // @description Records Snowager attempts and blasts; adds quick links on the Snowager page
5 | // @author senerio
6 | // @match *://*.neopets.com/winter/snowager.phtml
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | function message(b, a) {
12 | $('#np_snowager').text(`${b} blasts of ${a} attempts`);
13 | }
14 |
15 | let [blasts, attempts] = localStorage?.getItem('np_snowager')?.split('/').map(i => parseInt(i)) || [0, 0];
16 | $('.snowager_content').append(`
`);
17 | message(blasts, attempts);
18 |
19 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
20 | if( !data.includes('Come back later.') ) {
21 | blasts += data.includes('snow_blast');
22 | localStorage.setItem('np_snowager', [blasts, ++attempts].join('/'));
23 | message(blasts, attempts);
24 | }
25 | })
26 |
27 | // Allows reset/deletion of saved counts when user adds "#reset" to the url
28 | window.addEventListener('hashchange', () => {
29 | if(location.hash == '#reset') {
30 | localStorage.removeItem('np_snowager');
31 | message(0,0);
32 | }
33 | })
34 |
35 | // Adds quick links on the page. If not needed, comment out / remove everything below
36 | const links = [
37 | ['Check Avatars', '/settings/neoboards/'],
38 | ['Go to Healing Springs', '/faerieland/springs.phtml'],
39 | ['Refresh', 'snowager.phtml']
40 | ]
41 | $('.snowager_content').append('' + links.map(i => `${ i[0] }` ).join(' ▪ ') + '
');
42 | $('.snowager_content').append('Windows: 6-7 am, 2-3 pm, 10-11 pm NST
');
43 |
--------------------------------------------------------------------------------
/obelisk.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Obelisk
3 | // @version 2024-03-25
4 | // @description Handle getting stuck after picking a faction/boon; displays boon details
5 | // @author senerio
6 | // @match *://*.neopets.com/prehistoric/battleground/
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // @run-at document-idle
10 | // ==/UserScript==
11 |
12 | // Stuck fix
13 | const obeliskScript = document.querySelector('#pageDesc + style + script') || document.querySelector('#pageDesc + script');
14 | if(obeliskScript) {
15 | const newObeliskScript = obeliskScript.innerHTML.replace(/_gaq.push.*;/g, '')
16 | obeliskScript.remove();
17 | document.body.appendChild(Object.assign(document.createElement("script"), { innerHTML: newObeliskScript }));
18 | }
19 |
20 | // Boon details
21 | const boons = {
22 | "bankbribery": "bank interest +3%",
23 | "blackmarket": "highlight exclusive items",
24 | "booksmarts": "+2-4 INT after reading",
25 | "cartogriphication": "Faerie Caverns direction",
26 | "cheaperdozen": "10NP Stock Market minimum",
27 | "doctorwho": "cures sick neopet in the springs",
28 | "doppelganger": "chance to reuse one-use BD items",
29 | "doublebubble": "chance of potion refill",
30 | "equipall": "+1 weapon slot",
31 | "fivefinger": "10% neopian shop discount",
32 | "grrraaaahhhhhh": "BD damage increase by 10%",
33 | "lolavies": "steal someone's avatar",
34 | "refreshquest": "one refresh per faerie quest",
35 | "rightround": "+1 wheel spin",
36 | "scratchmaster": "+1 scratchcard purchase",
37 | "strengthmind": "Mind Blast BD ability (based on INT)",
38 | "millionairefeeling": "TP offer limit up to 2m (useless)",
39 | "fullpockets": "+NP from premium scratch card",
40 | "premiumdream": "+1 send score on featured game"
41 | }
42 | $('.perks li div').each((i,e) => {
43 | const name = e.style['background-image'].match('obelisk/(.*)_')[1];
44 | $(e).parent().append(`${boons[name]}
`);
45 | })
46 |
--------------------------------------------------------------------------------
/shopwizard.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Shop Wizard clear button, etc.
3 | // @version 2024-04-17
4 | // @description Add button to clear and focus on shop wizard search fields; open super shop wizard with search string upon loading shop wizard page; resubmit form
5 | // @author senerio
6 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
7 | // @match *://*.neopets.com/*
8 | // @grant GM_addStyle
9 | // ==/UserScript==
10 |
11 | // Add clear button to SW/SSW search fields
12 | ['#ssw_tabs_pane #searchstr', '#searchstr', '#shopwizard'].forEach(selector => {
13 | const position = (selector == '#ssw_tabs_pane #searchstr') ? 'font-size: 25px; top: -30px; left: 340px;' : 'font-size: 35px; top: -12px; left: -35px;' ;
14 | const style = 'width: 0; height: 0; overflow-x: visible; position: relative; cursor: pointer; color: #1c4070; '.concat(position);
15 | const element = $(selector);
16 | if(!element.length) { return; }
17 | element.after(`⟲
`);
18 | element.next()[0].addEventListener('click', function() {
19 | document.querySelector(selector).value = '';
20 | document.querySelector(selector).focus();
21 | })
22 | })
23 |
24 | // Upon loading SW page, automatically open SSW and copy search string
25 | const sswButton = $('.navsub-ssw-icon__2020');
26 | if( document.URL.includes('/shops/wizard.phtml') && sswButton.length ) {
27 | $('#ssw__2020').css('display', 'block');
28 | $('#searchstr').val($('#shopwizard').val());
29 | }
30 |
31 | // Make resubmit form on SW visible to change item name/price without clicking on new search
32 | if(document.URL.includes('/shops/wizard.phtml')) {
33 | GM_addStyle('#wresultform input[type=text] { border: 1px solid #3b79d6; padding: 0 0.5em; border-radius: 0.5em; box-sizing: border-box; font-family: "MuseoSansRounded500", "Arial", sans-serif; } input[name=rs_type] {width: 200px; }input[name=rs_min_price], input[name=rs_max_price] { width: 100px; }');
34 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
35 | if(settings.url.includes('/np-templates/ajax/wizard.php')) {
36 | $('#resubmitWizard').parent().prepend($('#resubmitWizard'));
37 | ['rs_type', 'rs_min_price', 'rs_max_price'].forEach(i => {
38 | $(`input[name=${i}]`).attr('type', 'text')
39 | });
40 | }
41 | });
42 | }
43 |
--------------------------------------------------------------------------------
/lostandpoundfilter.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Lost and Pound filter
3 | // @version 2024-06-02
4 | // @description Filter pets
5 | // @author senerio
6 | // @match https://lost.quiggle.org/*
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant GM_addStyle
9 | // ==/UserScript==
10 |
11 | // name filters:
12 | // \d - with numbers
13 | // ^[A-Z] - starts with caps
14 | // ^.+[A-Z] - no caps in the middle
15 | // _ - with underscores
16 |
17 | const included = {
18 | name: '',
19 | gender: '',
20 | species: [],
21 | colors: []
22 | }
23 | const excluded = {
24 | name: /\d/,
25 | gender: '',
26 | species: [],
27 | colors: []
28 | }
29 | const exception = {
30 | meta: ['Y1,', 'Y2,', 'Y3,']
31 | }
32 |
33 | // For browsing on mobile
34 | GM_addStyle("body { font-size: xx-large; } #petlist { width: 100%;} ");
35 |
36 | function removeIf(element, action, property, value) {
37 | if(property=='name') {
38 | if(
39 | (action=='exclude' && value.match(excluded[property])) ||
40 | (action=='include' && !value.match(included[property]))
41 | ) {
42 | element.remove();
43 | }
44 | }
45 | else if(
46 | ( action=='exclude' && excluded[property].includes(value) ) ||
47 | ( action=='include' && included[property].length > 0 && !included[property].includes(value) )
48 | ) {
49 | element.remove();
50 | }
51 | }
52 | document.querySelectorAll('div.pet').forEach(e => {
53 |
54 | // ignore filters for exceptions
55 | if( exception.meta.some(i=> e.querySelector('.petmeta').innerText.includes(i)) ) {
56 | console.log(e.querySelector('.petmeta').innerText)
57 | return;
58 | }
59 |
60 | // filter
61 |
62 | let name, temp, color, species;
63 |
64 | const gender = e.classList[1];
65 | removeIf(e, 'exclude', 'gender', gender);
66 | removeIf(e, 'include', 'gender', gender);
67 |
68 | if(e.querySelector('.petname')) {
69 | [name, temp, color, species] = e.querySelector('.petname a').innerText.split(' ');
70 | removeIf(e, 'exclude', 'colors', color);
71 | removeIf(e, 'include', 'colors', color);
72 | removeIf(e, 'exclude', 'species', species);
73 | removeIf(e, 'include', 'species', species);
74 |
75 | removeIf(e, 'exclude', 'name', name);
76 | removeIf(e, 'include', 'name', name);
77 | }
78 | });
79 |
--------------------------------------------------------------------------------
/compactquestlog.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Compact Quest Log
3 | // @version 2025-07-27-2
4 | // @description Removes extra spaces and other elements from the quest log
5 | // @author senerio
6 | // @match *://*.neopets.com/questlog/
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // ==/UserScript==
10 |
11 | const css = `
12 | /* Hide elements */
13 | .questlog-header,
14 | .questlog-info,
15 | .ql-bonus-label,
16 | .ql-desc,
17 | .ql-dots,
18 | .ql-progress,
19 | .ql-quest-top {
20 | display: none !important;
21 | }
22 |
23 | /* Top */
24 | #QuestLogStreakRewards.ql-hidden {
25 | display: block !important;
26 | }
27 |
28 | .questlog-top {
29 | gap: unset;
30 | }
31 |
32 | /* Bonus images and rewards */
33 | .ql-bonus-img {
34 | width: 40px !important;
35 | height: 40px !important;
36 | flex-shrink: 0 !important;
37 | margin-right: 0.5em !important;
38 | }
39 |
40 | .ql-bonus-img img {
41 | width: 100% !important;
42 | }
43 |
44 | .ql-bonus-reward {
45 | flex-direction: row !important;
46 | }
47 |
48 | #QuestLogReroll {
49 | position: unset !important;
50 | margin: 0 10px !important;
51 | }
52 |
53 | .missed-day-button {
54 | padding-top: 0 !important;
55 | padding-bottom: 0 !important;
56 | }
57 |
58 | .ql-bonus-check {
59 | top: 0 !important;
60 | width: 100% !important;
61 | }
62 |
63 | /* Rewards */
64 | .questlog-quests,
65 | .questlog-body {
66 | gap: 0.2em !important;
67 | }
68 |
69 | .ql-reward-img img,
70 | .ql-reward-np {
71 | width: 40px !important;
72 | height: 40px !important;
73 | margin-top: 2px !important;
74 | }
75 |
76 | .ql-reward {
77 | gap: 0 !important;
78 | padding: 0 1em !important;
79 | }
80 |
81 | /* Details */
82 | .ql-quest-details {
83 | display: flex !important;
84 | flex-wrap: wrap-reverse !important;
85 | justify-content: space-between !important;
86 | align-items: start !important;
87 | }
88 |
89 | .ql-quest-details > div {
90 | padding: 0 0.5em !important;
91 | }
92 |
93 | .ql-quest-description {
94 | width: 100% !important;
95 | }
96 |
97 | .ql-tasks {
98 | flex: 4 4 70% !important;
99 | margin: unset !important;
100 | }
101 |
102 | .ql-quest-buttons {
103 | flex: 1 1 20% !important;
104 | margin-top: 0 !important;
105 | display: flex !important;
106 | justify-content: center !important;
107 | }
108 |
109 | .ql-claim {
110 | margin: 0 !important;
111 | align-self: center !important;
112 | }
113 | `;
114 |
115 | document.head.insertAdjacentHTML('beforeend', ``);
116 |
--------------------------------------------------------------------------------
/plotvoidessence.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Plot: Void Essence Helper
3 | // @version 2024-07-08
4 | // @description Assists in collecting void essence by hiding the map image for easier clicking
5 | // @author senerio
6 | // @match *://*.neopets.com/altador/index.phtml
7 | // @match *://*.neopets.com/medieval/brightvale.phtml
8 | // @match *://*.neopets.com/medieval/index_evil.phtml
9 | // @match *://*.neopets.com/faerieland/faeriecity.phtml
10 | // @match *://*.neopets.com/faerieland/index.phtml
11 | // @match *://*.neopets.com/halloween/index.phtml
12 | // @match *://*.neopets.com/worlds/index_kikolake.phtml
13 | // @match *://*.neopets.com/pirates/index.phtml
14 | // @match *://*.neopets.com/moon/index.phtml
15 | // @match *://*.neopets.com/tropical/index.phtml
16 | // @match *://*.neopets.com/water/index.phtml
17 | // @match *://*.neopets.com/medieval/index_farm.phtml
18 | // @match *://*.neopets.com/medieval/index.phtml
19 | // @match *://*.neopets.com/medieval/index_castle.phtml
20 | // @match *://*.neopets.com/magma/caves.phtml
21 | // @match *://*.neopets.com/magma/index.phtml
22 | // @match *://*.neopets.com/island/index.phtml
23 | // @match *://*.neopets.com/objects.phtml
24 | // @match *://*.neopets.com/market_bazaar.phtml
25 | // @match *://*.neopets.com/market_map.phtml
26 | // @match *://*.neopets.com/market_plaza.phtml
27 | // @match *://*.neopets.com/halloween/neovia.phtml
28 | // @match *://*.neopets.com/desert/qasala.phtml
29 | // @match *://*.neopets.com/worlds/index_roo.phtml
30 | // @match *://*.neopets.com/desert/sakhmet.phtml
31 | // @match *://*.neopets.com/shenkuu/index.phtml
32 | // @match *://*.neopets.com/winter/index.phtml
33 | // @match *://*.neopets.com/winter/icecaves.phtml
34 | // @match *://*.neopets.com/winter/terrormountain.phtml
35 | // @match *://*.neopets.com/halloween/index_fair.phtml
36 | // @match *://*.neopets.com/worlds/index_geraptiku.phtml
37 | // @match *://*.neopets.com/desert/index.phtml
38 | // @match *://*.neopets.com/water/index_ruins.phtml
39 | // @match *://*.neopets.com/prehistoric/index.phtml
40 | // @match *://*.neopets.com/prehistoric/plateau.phtml
41 | // @match *://*.neopets.com/space/hangar.phtml
42 | // @match *://*.neopets.com/space/recreation.phtml
43 | // @match *://*.neopets.com/space/index.phtml
44 | // @match *://*.neopets.com/pirates/warfwharf.phtml
45 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
46 | // @grant GM_addStyle
47 | // ==/UserScript==
48 |
49 | /* // add count to page title
50 | const waitExist = setInterval(function() {
51 | const voidEssenceCount = $('.tvw-essence').length;
52 | if (voidEssenceCount) {
53 | document.title = `(${voidEssenceCount}) `.concat(document.title);
54 | clearInterval(waitExist);
55 | }
56 | }, 1000);
57 | */
58 |
59 | // hide map to show only essences
60 | GM_addStyle(`#canvas { display: none!important; }`)
--------------------------------------------------------------------------------
/questloglinks.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Quest Log Links
3 | // @version 2025-07-27
4 | // @description Adds quick links to quests
5 | // @author senerio
6 | // @match *://*.neopets.com/questlog/
7 | // @icon https://www.google.com/s2/favicons?sz=64&domain=neopets.com
8 | // @grant none
9 | // @run-at document-end
10 | // ==/UserScript==
11 |
12 | function waitForElement(condition = 'exist', selector, callback, { root = document.body } = {}) {
13 | let element = document.querySelector(selector);
14 | if (element && condition == 'exist') {
15 | callback(element);
16 | return () => {};
17 | }
18 |
19 | const observer = new MutationObserver((mutations, obs) => {
20 | callback(element);
21 | obs.disconnect();
22 | if (condition === 'change') {
23 | const elementObserver = new MutationObserver((mutations) => {
24 | callback(element);
25 | elementObserver.disconnect();
26 | });
27 | elementObserver.observe(element, { childList: true, subtree: true, attributes: true });
28 | }
29 | });
30 |
31 | observer.observe(root, { childList: true, subtree: true, attributes: true });
32 | return () => observer.disconnect();
33 | }
34 |
35 | const originalFetch = window.fetch;
36 | window.fetch = async (url, options = {}) => {
37 | const response = await originalFetch(url, options);
38 | if (response.url.includes('retrieveQuests') && response.ok) {
39 | waitForElement('change', '#QuestLogQuests', replaceQuestDescriptions);
40 | }
41 | return response;
42 | };
43 |
44 | function replaceQuestDescriptions() {
45 |
46 | const createLink = (url, text = 'Link') => {
47 | return Object.assign(document.createElement('a'), {
48 | href: url,
49 | target: '_blank',
50 | innerHTML: `◦ ${text} `
51 | });
52 | }
53 |
54 | const descriptionLinks = {
55 | "Customise": [
56 | { url: "https://www.neopets.com/customise/" }
57 | ],
58 | "Play any Game or Classic Game in the Games Room": [
59 | { url: "https://www.neopets.com/games/game.phtml?game_id=805&size=small&quality=low&play=true" }
60 | ],
61 | "Wheel of Mediocrity": [
62 | { url: "https://www.neopets.com/prehistoric/mediocrity.phtml" }
63 | ],
64 | "Wheel of Excitement": [
65 | { url: "https://www.neopets.com/faerieland/wheel.phtml" }
66 | ],
67 | "Wheel of Knowledge": [
68 | { url: "https://www.neopets.com/medieval/knowledge.phtml" }
69 | ],
70 | "Wheel of Misfortune": [
71 | { url: "https://www.neopets.com/halloween/wheel/index.phtml" }
72 | ],
73 | "Groom": [
74 | { url: "https://www.neopets.com/safetydeposit.phtml?obj_name=&category=10" }
75 | ],
76 | "Feed": [
77 | { url: "https://www.neopets.com/safetydeposit.phtml?offset=0&obj_name=&category=18" }
78 | ],
79 | "Purchase item(s) from any Neopian Shop": [
80 | { url: "https://www.neopets.com/faerieland/springs.phtml", text: "Springs" },
81 | { url: "https://www.neopets.com/generalstore.phtml", text: "General Store" },
82 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=7", text: "Magical Bookshop" },
83 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=38", text: "Faerieland Bookshop" },
84 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=51", text: "Sutek's Scrolls" },
85 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=70", text: "Booktastic Books" },
86 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=77", text: "Brightvale Books" },
87 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=92", text: "Words of Antiquity" },
88 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=106", text: "Neovian Printing Press" },
89 | { url: "https://www.neopets.com/objects.phtml?type=shop&obj_type=114", text: "Moltaran Books" }
90 | ]
91 | };
92 |
93 | document.querySelectorAll('.ql-quest-description').forEach(desc => {
94 | let descText = desc.textContent;
95 | desc.textContent = '';
96 | for (const [key, links] of Object.entries(descriptionLinks)) {
97 | if (descText.includes(key)) {
98 | links.forEach(link => {
99 | desc.appendChild(createLink(link.url, link.text));
100 | });
101 | }
102 | }
103 | });
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/stampscollected.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Mark Stamps Collected
3 | // @version 2024-07-12
4 | // @description Mark stamps collected in various pages
5 | // @author senerio
6 | // @match *://*.neopets.com/stamps.phtml?*type=*
7 | // @match *://*.neopets.com/inventory.phtml
8 | // @match *://*.neopets.com/objects.phtml?*obj_type=*
9 | // @match *://*.neopets.com/browseshop.phtml?*owner=*
10 | // @match *://*.neopets.com/safetydeposit.phtml*
11 | // @match *://*.neopets.com/quickstock.phtml*
12 | // @match *://*.neopets.com/island/tradingpost.phtml*
13 | // @match *://*.neopets.com/auctions.phtml*
14 | // @match *://*.neopets.com/genie.phtml*
15 | // @run-at document-end
16 | // ==/UserScript==
17 |
18 | //////////////////////////////////////////////////////
19 | // INSTRUCTIONS
20 | // 1. Visit all album pages: https://www.neopets.com/stamps.phtml?type=progress
21 | // 2. If you want to clear the saved data, click the reset button, top right of the album pages
22 | //////////////////////////////////////////////////////
23 |
24 | const itemStorage = {
25 | 'key': 'np_stampscollected',
26 | 'get': function() {
27 | return JSON.parse(localStorage?.getItem(this.key)) || [];
28 | },
29 | 'add': function(arr) {
30 | const collection = itemStorage.get().concat(arr);
31 | localStorage?.setItem(this.key, JSON.stringify(collection));
32 | },
33 | 'clear': function() {
34 | localStorage?.removeItem(this.key);
35 | }
36 | }
37 |
38 | const collectionPage = {
39 | 'updateTotalDisplay': () => {
40 | $('#np_total').text(`(Total: ${itemStorage.get().length})`);
41 | },
42 | 'deleteData': function() {
43 | itemStorage.clear();
44 | this.updateTotalDisplay();
45 | },
46 | 'storeItemsPresent': function() {
47 | const itemsStored = itemStorage.get();
48 | const itemsPresent = $('.content table img[alt]:not([alt="No Stamp"])').toArray().map(e => e.title);
49 | const itemsNew = itemsPresent.filter(i => !itemsStored.includes(i));
50 | if(itemsNew.length) {
51 | itemStorage.add(itemsNew);
52 | collectionPage.updateTotalDisplay();
53 | }
54 | },
55 | 'displayInitialize': function() {
56 | // delete data button
57 | $('.content').prepend(
58 | $('⟲')
59 | .click(this.deleteData.bind(this))
60 | );
61 | // counter
62 | $('.content b:contains("Neopian Post Office")').after(` `);
63 | this.updateTotalDisplay();
64 | }
65 | }
66 |
67 | // functions for pages with items to mark as obtained ////
68 |
69 | function markItems(elementsWithItemName, table = false) {
70 | elementsWithItemName.each(function() {
71 | const itemName = $(this);
72 | const isObtained = itemStorage.get().includes( itemName.text().split('(')[0].trim() )
73 | console.log(isObtained)
74 | if(isObtained) {
75 | itemName.css('text-decoration', 'line-through');
76 | itemName.parent().css('opacity', '50%');
77 | if(table) itemName.parent().parent().find('img').eq(0).css('opacity', '50%');
78 | }
79 | });
80 | }
81 |
82 | const pages = [
83 | {
84 | name: 'inventory',
85 | pageMatcher: /inventory/,
86 | itemNameObject: '.item-name'
87 | },
88 | {
89 | name: 'neopian shop',
90 | pageMatcher: /type=shop/,
91 | itemNameObject: $('.item-name')
92 | },
93 | {
94 | name: 'user shop',
95 | pageMatcher: /browseshop/,
96 | itemNameObject: $('a[href*=buy_item] + br + b')
97 | },
98 | {
99 | name: 'sdb',
100 | pageMatcher: /safetydeposit/,
101 | itemNameObject: $('.content form>table').eq(1).find('tr:not(:first-child):not(:last-child) td:nth-child(2) > b'),
102 | table: true
103 | },
104 | {
105 | name: 'quick stock',
106 | pageMatcher: /quickstock/,
107 | itemNameObject: $('form[name=quickstock] tr:not(:nth-last-child(2)) td:first-child:not([colspan])'),
108 | table: true
109 | },
110 | {
111 | name: 'trading post',
112 | pageMatcher: /tradingpost/,
113 | itemNameObject: $('img[src*="/items/"]').parent()
114 | },
115 | {
116 | name: 'auctions',
117 | pageMatcher: /auctions|genie/,
118 | itemNameObject: $('.content a[href*=auction_id]:not(:has(img))'),
119 | table: true
120 | }
121 | ]
122 |
123 | //////////////////////////////////////////////////////
124 |
125 | const loc = window.location.href;
126 | if(loc.includes('stamps')) {
127 | collectionPage.displayInitialize();
128 | if(loc.includes('type=album') && !loc.includes('page_id=0')) {
129 | collectionPage.storeItemsPresent();
130 | }
131 | }
132 | else if(!loc.match('stamps') && localStorage.hasOwnProperty(itemStorage.key)) {
133 | const page = pages.find((i) => loc.match(i.pageMatcher));
134 | if( ['inventory'].includes(page.name) ) {
135 | // for pages that fetch items with ajax call
136 | $(document).on('ajaxSuccess', () => {
137 | markItems($(page.itemNameObject));
138 | });
139 | }
140 | else {
141 | markItems(page.itemNameObject);
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## [Helper for JN SDB Price Checker](jnsdbhelper.user.js)
2 | Saves items in a list as you visit the pages of your SDB. Adds a textarea below the SDB which contains the source code of all the items saved so far, which you can copy and paste to [Jellyneo's SDB Price Checker Tool](https://items.jellyneo.net/tools/sdb-price-checker/).
3 | 
4 |
5 | ## [Mark Stamps Collected](stampscollected.user.js)
6 | Marks stamps you have already added to your album in locations like inventory, sdb, etc. Visit all pages of your [stamp album](https://www.neopets.com/stamps.phtml?type=progress) to save/update the list of stamps.
7 |
8 | Works similarly to [Mark Books Read](#mark-books-read).
9 |
10 | ## [Plot: Void Essence](plotvoidessence.user.js)
11 | * Assists in collecting void essence by hiding the map image for easier clicking. Disable script when not collecting to show and interact with the map.
12 |
13 | ## [Last SW Price](lastswprice.user.js)
14 | * Indicates your last SW/SSW search price on various pages
15 | 
16 |
17 | ## [Petpet Puddle and Lab Ray](petpetpuddle.user.js)
18 | * Fix page display if user has many petpets
19 | 
20 |
21 | ## [Brain Tree Helper](braintreehelper.user.js)
22 | * Saves Brain Tree answers from The Esophagor
23 | * Adds link back to Brain Tree
24 | 
25 |
26 | ## [Expand Neopets Sliders](expandslider.user.js)
27 |
28 | * Remove the horizontal slider to view all Neopets at once for pages like lab ray, monthly freebies, pound transfer
29 |
30 | ## [Remember Last Zap](rememberzap.user.js)
31 |
32 | * Remembers last selected pet in the lab ray
33 |
34 | ## [Training](training.user.js)
35 |
36 | * Skips the main page and redirects to status page
37 | * Begin training from the status page
38 |
39 | 
40 |
41 | After clicking "+" next to Str stat:
42 |
43 | 
44 |
45 | ## [Snowager Counter](snowager.user.js)
46 |
47 | * Records Snowager attempts and blasts
48 | * To delete/reset count, append "#reset" to the URL
49 | * Displays customizeable quick links
50 |
51 | 
52 |
53 | ## [Mark Books Read](booksread.user.js)
54 |
55 | Marks books your pet has already read on the following locations: inventory, neopian shops, user shops, sdb, quick stock, trading post, auctions. Visit the pet's [Neopian books read](https://www.neopets.com/books_read.phtml?pet_name=) and [Booktastic books read](https://www.neopets.com/moon/books_read.phtml?pet_name=) pages to save/update the list of books.
56 | 
57 | 
58 | 
59 |
60 | Additional screenshots:
61 | [books read page](https://i.imgur.com/8LpPqGi.png),
62 | [quick stock](https://i.imgur.com/KW9QBpM.png),
63 | [user shops](https://i.imgur.com/qD57RbP.png),
64 | [trading post](https://i.imgur.com/kToPIc6.png),
65 | [auctions](https://i.imgur.com/9fLSfZX.png),
66 | [auction genie](https://i.imgur.com/hq4KPjP.png)
67 |
68 | ## [Inventory Divider](inventorydivider.user.js)
69 |
70 | Separates auctioned/trading items in the inventory
71 | 
72 |
73 | ## [Obelisk](obelisk.user.js)
74 |
75 | * Handle getting stuck after picking a faction/boon
76 | * Displays boon details
77 | 
78 |
79 | ## Quest Log
80 |
81 | ### [Compact Quest Log](compactquestlog.user.js)
82 | ### [Quest Log Links](questloglinks.user.js)
83 |
84 | 
85 |
86 | ### [Quest Log navigation button](questlogbutton.user.js)
87 |
88 | Lets you open the Quest Log in a new tab from the button on the navigation bar
89 | 
90 |
91 | ## [Wishing Well autofill](wishingwell.user.js)
92 |
93 | 
94 |
95 | ## [Stock Market autofill](stockmarket.user.js)
96 |
97 | Picks any 15NP (10NP if with boon) stock to autofill with the max number of shares. Visit the bargain or full list first, then the buy page.
98 | 
99 |
100 | ## [Scratch Cards](scratchcard.user.js)
101 |
102 | * Adds return link to play again
103 | 
104 | * Automatically picks the first card
105 | 
106 |
107 | ## [Lunar Temple answer highlight](lunartemple.user.js)
108 |
109 | 
110 |
111 | ## [Shop Wizard](shopwizard.user.js)
112 |
113 | * Adds clear search field button
114 | 
115 |
116 | * Automatically opens SSW when on the SW page. If URL has the item name (eg. opened from Jellyneo or ItemDB), places the name on the search fields.
117 | 
118 |
119 | * Allows changing the search name/minimum price/maximum price of the resubmit button from the Shop Wizard result page
120 | 
121 |
122 | ## Food Club
123 |
124 | ### [Current Bets counter](fcbetcount.user.js)
125 |
126 | 
127 | 
128 |
129 | ### [NeoFoodClub quick links](nfclinks.user.js)
130 |
131 | Links to check max bet, bank, collect, current bets. Remove last 2 lines if you want to see the edit and copy buttons.
132 | 
133 |
134 | ## [Uncategorized Gallery items](galleryquickcat.user.js)
135 |
136 | For easier management of uncategorized items via Quick Categories
137 | * Hide all categorized items
138 | 
139 | * Original view
140 | 
141 | * Check all uncategorized items
142 | 
143 |
144 | ## DTI
145 |
146 | ### [Neoboards links](neoboardlinks.user.js)
147 | Makes Neopets, DTI links clickable on Neoboards posts
148 |
149 | ### [Tradelist sticky headers](dtistickyheader.user.js)
150 | Shows you the name of the current section as you scroll
151 |
152 | ## [Lost and Pound filter](lostandpoundfilter.user.js)
153 | Shows only desired gender/color/species/year, and hide those with unwanted characters in the name. Text size is enlarged for browsing on mobile.
154 |
--------------------------------------------------------------------------------
/booksread.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Mark Books Read
3 | // @version 2025-07-26
4 | // @description Mark books read in: inventory, neopian shops, user shops, sdb, quick stock, trading post, auctions
5 | // @author senerio
6 | // @match *://*.neopets.com/books_read.phtml?pet_name=*
7 | // @match *://*.neopets.com/moon/books_read.phtml?pet_name=*
8 | // @match *://*.neopets.com/inventory.phtml
9 | // @match *://*.neopets.com/objects.phtml?*obj_type=*
10 | // @match *://*.neopets.com/browseshop.phtml?*owner=*
11 | // @match *://*.neopets.com/safetydeposit.phtml*
12 | // @match *://*.neopets.com/quickstock.phtml*
13 | // @match *://*.neopets.com/island/tradingpost.phtml*
14 | // @match *://*.neopets.com/auctions.phtml*
15 | // @match *://*.neopets.com/genie.phtml*
16 | // @match *://*.neopets.com/generalstore.phtml*
17 | // @match *://items.jellyneo.net/search/*
18 | // @connect itemdb.com.br
19 | // @grant GM_xmlhttpRequest
20 | // @run-at document-end
21 | // ==/UserScript==
22 |
23 | //////////////////////////////////////////////////////
24 | // INSTRUCTIONS
25 | // 1. Set reader name
26 | const petName = '';
27 | // 2. Visit pet's books read pages (redo this step whenever you'd like to update)
28 | // - https://www.neopets.com/books_read.phtml?pet_name=
29 | // - https://www.neopets.com/moon/books_read.phtml?pet_name=
30 | // 3. If you want to clear the saved data, click the reset button, top right of the books read pages
31 | //////////////////////////////////////////////////////
32 |
33 | // functions for books read pages ////////////////////
34 |
35 | function itemdbGetItemName(array) { // SMH BOOKTASTIC BOOKS PAGE WHY NO BOOK NAME / SMH QUICK STOCK WHY NO ITEM IMG
36 | return new Promise((resolve, reject) => {
37 | GM_xmlhttpRequest({
38 | method: 'POST',
39 | url: 'https://itemdb.com.br/api/v1/items/many',
40 | headers: {'Content-Type': 'application/json'},
41 | data: JSON.stringify({
42 | image_id: array
43 | }),
44 | onload: function (res) {
45 | if (res.status === 200) {
46 | const itemData = [];
47 | Object.entries(JSON.parse(res.responseText)).forEach(([k,v]) => { itemData.push(v.name); });
48 | resolve(itemData);
49 | return console.log('[itemdb] Fetched item data');
50 | }
51 | else {
52 | const msg = '[itemdb] Failed to fetch item data';
53 | return console.error(msg, res);
54 | }
55 | },
56 | onerror: function (err) {
57 | reject(err);
58 | }
59 | });
60 | });
61 | }
62 |
63 | const booksReadStorage = {
64 | 'key': 'np_booksread',
65 | 'get': function() {
66 | return JSON.parse(localStorage?.getItem(this.key)) || {};
67 | },
68 | 'set': function(arr) { // [ {books, key, append} ]
69 | const books = booksReadStorage.get();
70 | arr.forEach(i => {
71 | if(!i.append) { books[i.key] = []; }
72 | (books[i.key] ??= []).push(...i.books);
73 | })
74 | localStorage?.setItem(this.key, JSON.stringify(books));
75 | },
76 | 'all': function() {
77 | const books = this.get();
78 | return [...books.neopian, ...books.booktastic];
79 | }
80 | }
81 |
82 | const booksReadPage = {
83 | 'type': window.location.pathname.includes('moon') ? 'booktastic' : 'neopian',
84 | 'updateBookCount': () => {
85 | const books = booksReadStorage.get();
86 | $('#np_booksread_count').text(`(${books.neopian?.length || 0} Neopian, ${books.booktastic?.length || 0} Booktastic)`);
87 | },
88 | 'deleteData': function() {
89 | const arr = [{
90 | books: [],
91 | key: this.type,
92 | append: false
93 | }];
94 | if(this.type == 'booktastic') {
95 | arr.push({ ...arr[0], key: arr[0].key.concat('Img') });
96 | }
97 | booksReadStorage.set(arr);
98 | this.updateBookCount();
99 | },
100 | 'storeBooksOnPage': async function() {
101 | const booksStored = booksReadStorage.get();
102 | const bookRows = $(".content table tr:not(:first-child)")
103 | if (bookRows.length == booksStored[this.type]?.length) { return; }
104 | // proceed if needs updating
105 | let booksOnPage = [];
106 | const arr = []
107 | if(this.type == 'neopian') {
108 | bookRows.find('td:last-child').each((i,e) => {
109 | booksOnPage.push( $(e).text().split(': \u00a0').at(0) );
110 | })
111 | booksReadStorage.set([{
112 | books: booksOnPage,
113 | key: 'neopian',
114 | append: false
115 | }]);
116 | }
117 | else if(this.type == 'booktastic') {
118 | bookRows.find('img').each((i,e) => {
119 | booksOnPage.push( $(e).attr('src').match(/.*\/(.*)\..*/).at(-1) );
120 | })
121 | const newBooks = booksOnPage.filter((i)=>{ return !booksStored.booktasticImg?.includes(i) });
122 | booksReadStorage.set([
123 | {
124 | books: booksOnPage,
125 | key: 'booktasticImg',
126 | append: false
127 | },
128 | {
129 | books: await itemdbGetItemName(newBooks),
130 | key: 'booktastic',
131 | append: true
132 | }
133 | ]);
134 | }
135 | this.updateBookCount();
136 | },
137 | 'displayInitialize': function() {
138 | // delete data button (only for specific page)
139 | $('.content').prepend(
140 | $('⟲')
141 | .click(this.deleteData.bind(this))
142 | );
143 | // counter
144 | $('.content > b:first-of-type').after(` `);
145 | this.updateBookCount();
146 | }
147 | }
148 |
149 | // functions for pages with books to mark as read ////
150 |
151 | function markBooks(elementsWithItemName, table = false) {
152 | elementsWithItemName.each(function() {
153 | const itemName = $(this);
154 | const isRead = booksReadStorage.all().includes( itemName.text().split('(')[0].trim() )
155 | if(isRead) {
156 | itemName.css('text-decoration', 'line-through');
157 | itemName.parent().css('opacity', '50%');
158 | if(table) itemName.parent().parent().find('img').eq(0).css('opacity', '50%');
159 | }
160 | });
161 | }
162 |
163 | const pages = [
164 | {
165 | name: 'inventory',
166 | pageMatcher: /inventory/,
167 | itemNameObject: '.item-name'
168 | },
169 | {
170 | name: 'neopian shop',
171 | pageMatcher: /type=shop/,
172 | itemNameObject: $('.item-name')
173 | },
174 | {
175 | name: 'user shop',
176 | pageMatcher: /browseshop/,
177 | itemNameObject: $('a[href*=buy_item] + br + b')
178 | },
179 | {
180 | name: 'sdb',
181 | pageMatcher: /safetydeposit/,
182 | itemNameObject: $('.content form>table').eq(1).find('tr:not(:first-child):not(:last-child) td:nth-child(2) > b'),
183 | table: true
184 | },
185 | {
186 | name: 'quick stock',
187 | pageMatcher: /quickstock/,
188 | itemNameObject: $('form[name=quickstock] tr:not(:nth-last-child(2)) td:first-child:not([colspan])'),
189 | table: true
190 | },
191 | {
192 | name: 'trading post',
193 | pageMatcher: /tradingpost/,
194 | itemNameObject: $('img[src*="/items/"]').parent()
195 | },
196 | {
197 | name: 'auctions',
198 | pageMatcher: /auctions|genie/,
199 | itemNameObject: $('.content a[href*=auction_id]:not(:has(img))'),
200 | table: true
201 | },
202 | {
203 | name: 'general store',
204 | pageMatcher: /generalstore/,
205 | itemNameObject: $(".contentModule:has(td.contentModuleHeader:contains('Books')) .contentModuleContent .item-title"),
206 | table: true
207 | },
208 | {
209 | name: 'Jellyneo Search',
210 | pageMatcher: /jellyneo.*search/,
211 | itemNameObject: $('.jnflex-grid p a.no-link-icon:nth-of-type(2)'),
212 | table: false
213 | }
214 | ]
215 |
216 | //////////////////////////////////////////////////////
217 |
218 | const loc = window.location.href;
219 | if(loc.match(/books_read/) && loc.includes(petName)) {
220 | booksReadPage.displayInitialize();
221 | booksReadPage.storeBooksOnPage();
222 | }
223 | else if(!loc.match(/books_read/) && localStorage.hasOwnProperty(booksReadStorage.key)) {
224 | const page = pages.find((i) => {
225 | return loc.match(i.pageMatcher)
226 | });
227 | if( ['inventory'].includes(page.name) ) { // for pages that fetch items with ajax call
228 | $(document).on('ajaxSuccess', () => {
229 | markBooks($(page.itemNameObject));
230 | });
231 | }
232 | else {
233 | markBooks(page.itemNameObject);
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/lastswprice.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Neopets - Last SW Price
3 | // @version 2024-08-26
4 | // @description Indicates your last SW/SSW search price on various pages
5 | // @author senerio
6 | // @match *://*.neopets.com/shops/wizard.phtml*
7 | // @match *://*.neopets.com/inventory.phtml
8 | // @match *://*.neopets.com/objects.phtml?*obj_type=*
9 | // @match *://*.neopets.com/browseshop.phtml?*owner=*
10 | // @match *://*.neopets.com/safetydeposit.phtml*
11 | // @match *://*.neopets.com/quickstock.phtml*
12 | // @match *://*.neopets.com/island/tradingpost.phtml*
13 | // @match *://*.neopets.com/auctions.phtml*
14 | // @match *://*.neopets.com/market.phtml*type=your*
15 | // @match *://*.neopets.com/market_your.phtml*
16 | // @match *://*.neopets.com/genie.phtml*
17 | // @match *://*.neopets.com/faerieland/darkfaerie.phtml*
18 | // @match *://*.neopets.com/medieval/earthfaerie.phtml*
19 | // @match *://*.neopets.com/winter/snowfaerie*.phtml*
20 | // @match *://*.neopets.com/island/kitchen*.phtml*
21 | // @match *://*.neopets.com/halloween/witchtower*.phtml*
22 | // @match *://*.neopets.com/halloween/esophagor*.phtml*
23 | // @match *://*.neopets.com/space/coincidence.phtml*
24 | // @match *://*.neopets.com/winter/igloo2.phtml*
25 | // @match *://*.neopets.com/donations.phtml*
26 | // @match *://*.neopets.com/halloween/garage.phtml*
27 | // @match *://*.neopets.com/thriftshoppe/*
28 | // @match *://*.neopets.com/faerieland/employ/employment.phtml*
29 | // @match *://*.neopets.com/games/kadoatery/*
30 | // @match *://*.neopets.com/island/training.phtml*
31 | // @match *://*.neopets.com/pirates/academy.phtml*
32 | // @match *://*.neopets.com/island/fight_training.phtml*
33 | // @grant GM_xmlhttpRequest
34 | // @grant GM_addStyle
35 | // @run-at document-end
36 | // ==/UserScript==
37 |
38 | // local storage
39 |
40 | const priceStorage = {
41 | 'key': 'np_lastsw',
42 | 'get': function(name) {
43 | const items = JSON.parse(localStorage?.getItem(this.key)) || {};
44 | return name ? items[name] : items;
45 | },
46 | 'set': function(name, price) {
47 | const items = priceStorage.get();
48 | items[name] = price;
49 | localStorage?.setItem(this.key, JSON.stringify(items));
50 | }
51 | }
52 |
53 | // pages
54 |
55 | function markItems(page) {
56 | const intl = new Intl.NumberFormat();
57 | const style = 'font-size: x-small; color: #5088d1; margin: auto; white-space: nowrap; font-weight: normal;';
58 |
59 | let itemNameObject;
60 | if(typeof(page.itemNameObject) == 'string') {
61 | itemNameObject = $(page.itemNameObject);
62 | }
63 | else {
64 | itemNameObject = page.itemNameObject;
65 | }
66 |
67 | itemNameObject.each(function() {
68 | const item = $(this);
69 | const itemName = (page.itemNameMatch ? item.text().match(page.itemNameMatch)[1] : item.text()).trim()
70 | const price = priceStorage.get(itemName);
71 | if(price) {
72 | const priceHTML = `SW: ${intl.format(price)} NP
`
73 | if(page.insert) {
74 | page.insert(item, priceHTML);
75 | }
76 | else {
77 | item.parent().append(priceHTML);
78 | }
79 | if(page.style) {
80 | GM_addStyle(page.style);
81 | }
82 | }
83 | });
84 | }
85 |
86 | const pages = [
87 | {
88 | name: 'inventory',
89 | pageMatcher: /inventory/,
90 | itemNameObject: '.item-name'
91 | },
92 | {
93 | name: 'neopian shop',
94 | pageMatcher: /type=shop|donations/,
95 | itemNameObject: $('.item-name')
96 | },
97 | {
98 | name: 'user shop',
99 | pageMatcher: /browseshop/,
100 | itemNameObject: $('a[href*=buy_item] + br + b'),
101 | insert: (e, insert) => { return e.parent().find('br').eq(-2).after(insert); }
102 | },
103 | {
104 | name: 'sdb',
105 | pageMatcher: /safetydeposit/,
106 | itemNameObject: $('.content form>table').eq(1).find('tr:not(:first-child):not(:last-child) td:nth-child(2) > b').map((i,v) => v.firstChild)
107 | },
108 | {
109 | name: 'quick stock',
110 | pageMatcher: /quickstock/,
111 | itemNameObject: $('form[name=quickstock] tr:not(:nth-last-child(2)) td:first-child:not([colspan])'),
112 | insert: (e, insert) => { return e.parent().find('td:nth-of-type(2)').append(insert); }
113 | },
114 | {
115 | name: 'trading post',
116 | pageMatcher: /tradingpost/,
117 | itemNameObject: $('img[src*="/items/"]').parent(),
118 | insert: (e, insert) => { return e.parent().find('td:nth-of-type(2)').append(insert); }
119 | },
120 | {
121 | name: 'auctions',
122 | pageMatcher: /auctions|genie/,
123 | itemNameObject: $('.content a[href*=auction_id]:not(:has(img))'),
124 | insert: (e, insert) => { return e.parent().parent().find('td:nth-last-of-type(2)').append(insert); }
125 | },
126 | {
127 | name: 'shop stock',
128 | pageMatcher: /market/,
129 | itemNameObject: $('form table').eq(0).find('tbody > tr').slice(1, -1 - 2*$('#pin_field').length).find('td:first-child b'),
130 | insert: (e, insert) => { return e.eq(0).parent().parent().find('td:nth-of-type(5)').append(insert); }
131 | },
132 | {
133 | name: 'ingredients',
134 | pageMatcher: /snowfaerie|kitchen|witchtower|esophagor/,
135 | itemNameObject: $('.ingredient-grid p b')
136 | },
137 | {
138 | name: 'illusen',
139 | pageMatcher: /earthfaerie/,
140 | itemNameObject: $('#earth-container div+p b')
141 | },
142 | {
143 | name: 'jhudora',
144 | pageMatcher: /darkfaerie/,
145 | itemNameObject: $('#dark-container div+p b')
146 | },
147 | {
148 | name: 'coincidence',
149 | pageMatcher: /coincidence/,
150 | itemNameObject: $('#questItems td'),
151 | itemNameMatch: /(.*)x\d+.*/,
152 | insert: (e, insert) => { return e.find('b').after(insert); }
153 | },
154 | {
155 | name: 'igloo',
156 | pageMatcher: /igloo/,
157 | itemNameObject: $('form[name=items_for_sale] td b')
158 | },
159 | {
160 | name: 'attic',
161 | pageMatcher: /garage/,
162 | itemNameObject: $('#items li b'),
163 | insert: (e, insert) => { return e.parent().find('br').eq(-2).after(insert); },
164 | style: '#items li { height: 180px !important; }'
165 | },
166 | {
167 | name: 'secondhand',
168 | pageMatcher: /thriftshoppe/,
169 | itemNameObject: $('.content table td a div:nth-child(2)')
170 | },
171 | {
172 | name: 'employment',
173 | pageMatcher: /employment/,
174 | itemNameObject: $('.content table td[colspan=2]'),
175 | itemNameMatch: / of: (.*)Time:/,
176 | insert: (e, insert) => { return e.parent().find('br').eq(1).before(insert); }
177 | },
178 | {
179 | name: 'kadoatery',
180 | pageMatcher: /kadoatery/,
181 | itemNameObject: $('.content strong:nth-of-type(2)')
182 | },
183 | {
184 | name: 'island training',
185 | pageMatcher: /training/,
186 | itemNameObject: $('img[src*="/items/"]').parent().find('b').map((i, v) => v.firstChild),
187 | insert: (e, insert) => { return e.parent().next().after(insert); }
188 | },
189 | {
190 | name: 'pirate academy',
191 | pageMatcher:/academy/,
192 | itemNameObject: $('img[src*="/items/"]').parent().parent().find('b')
193 | }
194 | ]
195 |
196 | //////////////////////////////////////////////////////
197 |
198 | const loc = window.location.href;
199 |
200 | // Save SW price
201 | if(loc.match(/shops\/wizard.phtml/) || $('#ssw-tabs').length) {
202 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
203 | let itemName, itemPrice;
204 |
205 | // SW
206 | if(settings.url.includes('/np-templates/ajax/wizard.php')) {
207 | itemName = $('.wizard-results-text h3').text();
208 | itemPrice = $('.wizard-results-grid li > a').eq(0).attr('href')?.match(/(?<=buy_cost_neopoints=)\d+/)[0];
209 | }
210 | // SSW
211 | else if(settings.url.includes('/shops/ssw/ssw_query.php')) {
212 | itemName = data.req.item_name; // $('#search_for').text().match(/matching '(.*)'/)[1];
213 | itemPrice = data.data.prices[0]; // $('#ssw-tabs .plink').eq(0).attr('href')?.match(/(?<=buy_cost_neopoints=)\d+/)[0]
214 | }
215 |
216 | if (itemPrice) priceStorage.set(itemName, itemPrice);
217 | })
218 | }
219 |
220 | // Display last SW price
221 | if(localStorage.hasOwnProperty(priceStorage.key)) {
222 | const page = pages.find((i) => {
223 | return loc.match(i.pageMatcher)
224 | });
225 | if( ['inventory'].includes(page?.name) ) { // for pages that fetch items with ajax call
226 | $(document).on('ajaxSuccess', function(event, xhr, settings, data) {
227 | if(settings.url.includes('/np-templates/ajax/inventory.php')) {
228 | markItems(page);
229 | }
230 | });
231 | }
232 | else if(page) {
233 | markItems(page);
234 | }
235 | }
236 |
--------------------------------------------------------------------------------