├── 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 = $(' 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 | ![jn sdb helper](https://i.imgur.com/5p7xrgV.png) 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 | ![last sw price - inventory](https://i.imgur.com/PChtlL3.png) 16 | 17 | ## [Petpet Puddle and Lab Ray](petpetpuddle.user.js) 18 | * Fix page display if user has many petpets 19 | ![petpet puddle](https://i.imgur.com/tQ5eBXQ.png) 20 | 21 | ## [Brain Tree Helper](braintreehelper.user.js) 22 | * Saves Brain Tree answers from The Esophagor 23 | * Adds link back to Brain Tree 24 | ![brain tree saved answers](https://i.imgur.com/AmnzoVg.png) 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 | ![training 1](https://i.imgur.com/7boIeEP.png) 40 | 41 | After clicking "+" next to Str stat: 42 | 43 | ![training 2](https://i.imgur.com/wby1eWy.png) 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 | ![snowager](https://i.imgur.com/HMJtSJB.png) 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 | ![books read - neopian shop](https://i.imgur.com/phFxsmH.png) 57 | ![books read - inventory](https://i.imgur.com/WNtDF5J.png) 58 | ![books read - sdb](https://i.imgur.com/F9KCVhj.png) 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 | ![inventory divider](https://i.imgur.com/qYcHM1o.png) 72 | 73 | ## [Obelisk](obelisk.user.js) 74 | 75 | * Handle getting stuck after picking a faction/boon 76 | * Displays boon details 77 | ![obelisk boons](https://i.imgur.com/LShzi3V.png) 78 | 79 | ## Quest Log 80 | 81 | ### [Compact Quest Log](compactquestlog.user.js) 82 | ### [Quest Log Links](questloglinks.user.js) 83 | 84 | ![compact quest log](https://i.imgur.com/0Bwz1a0.png) 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 | ![quest log navigation button](https://i.imgur.com/MuhxERS.png) 90 | 91 | ## [Wishing Well autofill](wishingwell.user.js) 92 | 93 | ![wishing well autofill](https://i.imgur.com/n0qwhZM.png) 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 | ![stock market autofill](https://i.imgur.com/7jFnDuZ.png) 99 | 100 | ## [Scratch Cards](scratchcard.user.js) 101 | 102 | * Adds return link to play again 103 | ![scratch again](https://i.imgur.com/iCAvweQ.png) 104 | * Automatically picks the first card 105 | ![scratchcard dropdown](https://i.imgur.com/HB31Xxn.png) 106 | 107 | ## [Lunar Temple answer highlight](lunartemple.user.js) 108 | 109 | ![lunar temple](https://i.imgur.com/BFR03KL.png) 110 | 111 | ## [Shop Wizard](shopwizard.user.js) 112 | 113 | * Adds clear search field button 114 | ![sw clear](https://i.imgur.com/NgXeFEh.png) 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 | ![ssw open](https://i.imgur.com/J3LduJ9.png) 118 | 119 | * Allows changing the search name/minimum price/maximum price of the resubmit button from the Shop Wizard result page 120 | ![sw resubmit](https://i.imgur.com/RVy2bTi.png) 121 | 122 | ## Food Club 123 | 124 | ### [Current Bets counter](fcbetcount.user.js) 125 | 126 | ![fc 0 bets](https://i.imgur.com/an0nUlL.png) 127 | ![fc 10 bets](https://i.imgur.com/PwrOJze.png) 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 | ![nfc links](https://i.imgur.com/lyZJl2q.png) 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 | ![quickcat hide categorized](https://i.imgur.com/EIDIvon.png) 139 | * Original view 140 | ![quickcat initial](https://i.imgur.com/oHIfz0e.png) 141 | * Check all uncategorized items 142 | ![quickcat check all uncategorized](https://i.imgur.com/jecQGm4.png) 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 | --------------------------------------------------------------------------------