您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Blocked users can be synced but do not actually change anything in the SW results yet.
// ==UserScript== // @name [GC] Organize SW Results // @namespace https://greasyfork.org/en/users/1225524-kaitlin // @match https://www.grundos.cafe/market/wizard* // @match https://www.grundos.cafe/guilds/guild/*/members* // @match https://www.grundos.cafe/block* // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js // @require https://update.greasyfork.org/scripts/487361/1389917/%5BGC%20%7C%20Library%5D%20-%20SSW%3A%20Savvy%20Shop%20Wiz.js // @grant GM.getValue // @grant GM.setValue // @grant GM.listValues // @license MIT // @version 2.0.1 // @author Cupkait // @icon https://i.imgur.com/4Hm2e6z.png // @description Blocked users can be synced but do not actually change anything in the SW results yet. // ==/UserScript== createSSWMenu(); addStyles(); let wizList = document.querySelector('.sw_results'); if (window.location.href.startsWith('https://www.grundos.cafe/market/wizard/') && wizList) { generateNewGrid(); } async function grabData() { const resultsGrid = document.querySelector('.sw_results'); const resultsRaw = resultsGrid.querySelectorAll('.data'); const rawData = []; for (var i = 0; i < resultsRaw.length;) { var seller = resultsRaw[i].innerText; console.log(seller) var link = resultsRaw[i].innerHTML; var stock = parseInt(resultsRaw[i + 2].innerText,10); var price = parseInt(resultsRaw[i + 3].innerText.replace(/[^\d]/g, ''), 10); var row = { seller: seller, link: link, stock: stock, price: price }; rawData.push(row); i = i + 4; } return rawData; } async function calculateValues() { let rawData = await grabData(); let lowestPrice = Math.min(...rawData.map(item => item.price)); rawData.forEach(item => { item.pricediff = item.price - lowestPrice; }); return rawData; } async function getUsers() { let friendList = await GM.getValue('friendList', '[]'); let guildsList = await GM.getValue('guildsList', '{}'); let blockList = await GM.getValue('blockList', '[]'); const guildMembers = Object.values(guildsList).flatMap(guild => guild.guildMembers); if (typeof friendList === 'string') { friendList = JSON.parse(friendList); } if (typeof guildMembers === 'string') { guildMembers = JSON.parse(guildMembers); } if (typeof blockList === 'string') { blockList = JSON.parse(blockList); } return { friendList, guildMembers, blockList }; } async function createTableRow(item, friendList, guildMembers, blockList) { var price = item.price.toLocaleString() + " NP"; let variance; let friendstatus = friendList.includes(item.seller); let guildstatus = guildMembers.includes(item.seller); let blockstatus = blockList.includes(item.seller); if (item.pricediff === 0) { variance = '<span style="color:green">— LOWEST —</span>'; } else if (friendstatus || guildstatus) { variance = `<span style="color:red">(+${item.pricediff.toLocaleString()})</span>`; } else { variance = '—'; } let row = document.createElement('tr'); row.innerHTML = ` <td>${item.link}</td> <td>${item.stock}</td> <td><strong>${price}</strong></td> <td><strong>${variance}</strong></td> `; if (friendstatus) { row.classList.add('friend'); } else if (blockstatus) { row.classList.add('blocked'); } else if (guildstatus) { row.classList.add('guild'); } return row; } async function generateNewGrid() { const { friendList, guildMembers, blockList } = await getUsers(); const newGrid = document.createElement('table'); newGrid.innerHTML = `<thead><tr><th>Owner</th><th>Stock</th><th>Price</th><th>Variance</th></tr></thead>`; let rawData = await calculateValues(); const newHeader = await updateHeader(); rawData.sort((a, b) => { const aIsFriend = friendList.includes(a.seller); const bIsFriend = friendList.includes(b.seller); const aIsGuildMember = guildMembers.includes(a.seller); const bIsGuildMember = guildMembers.includes(b.seller); if ((aIsFriend || aIsGuildMember) && !(bIsFriend || bIsGuildMember)) return -1; if (!(aIsFriend || aIsGuildMember) && (bIsFriend || bIsGuildMember)) return 1; return 0; }); const tbody = document.createElement('tbody'); for (const item of rawData) { const row = await createTableRow(item, friendList, guildMembers, blockList); tbody.appendChild(row); } newGrid.appendChild(tbody); const oldGrid = document.querySelector('.sw_results'); oldGrid.insertAdjacentElement('beforebegin', newGrid); oldGrid.style.display = 'none'; } async function updateHeader() { } function addStyles() { const newGridStyle = document.createElement('style'); newGridStyle.innerHTML = ` #sswmenu { display: none; border-radius: 15px 15px 15px 0px; border-bottom: 3px solid; position: absolute; z-index: 999; width: 250px; height: 250px; bottom: 0%; left: 100%; margin: -3px; padding: 10px; background-color: #d2d0cc; box-shadow: 5px 0 5px rgba(0, 0, 0, 0.5); } #sswcontainer { position: relative; border-bottom: 3px solid; padding: 5px 10px 5px 0px; height: 30px; width: 100%; top: 00%; left: 0px; background-color: #d2d0cc; box-shadow: 5px 0 5px rgba(0, 0, 0, 0.5); } #sswsettings { position: relative; font-size: 16px; font-weight: bold; font-family: courier; border-radius: 5px; padding: 5px; width: 100%; height: auto; border: 1px solid rgb(204, 204, 204); cursor: pointer; background-color: lightgray; } #menubutton { height: 35px; width: 90%; margin: 5px; } table { position: relative; min-width: 80%; margin: 1em auto; width: max-content; max-width: 100%; text-align: center; border-collapse: collapse; } th, td { position: relative; padding: 4px; z-index: 3; } th { background-color: var(--grid_head); } tr { position: relative; min-width: 100%; margin: 1em auto; width: max-content; max-width: 100%; text-align: center; border-collapse: collapse; } tr:nth-child(even) { background-color: var(--grid_even); } tr:nth-child(odd) { background-color: var(--grid_odd); } .friend::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #00801a54; z-index: 1; } .guild::after { content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #2c008054; z-index: 1; } .blocked { opacity:10% } .blocked:hover { opacity:85% } `; document.head.appendChild(newGridStyle); } // SYNCING BELOW function removeUsersManually() { var userInput = prompt( 'Which username would you like to remove from your list? Enter one username then click OK.' ); if (userInput !== null && userInput.trim() !== '') { var index = friendList.findIndex(name => name .toLowerCase() === userInput.trim().toLowerCase()); if (index !== -1) { friendList.splice(index, 1); GM.setValue('friendList', friendList); console.log('Removed', userInput.trim(), 'from the friend list.'); } else { console.log(userInput.trim(), 'not found in the friend list.'); } if (window.location.href === 'https://www.grundos.cafe/market/wizard/') { if (confirm( 'Do you want to reload the page to see the updated results?' )) { location.reload(); } } } else { console.log('No username entered. Operation canceled.'); } } $(ManualRemove).on('click', removeUsersManually); async function syncFriendsList() { try { const response = await fetch( 'https://www.grundos.cafe/neofriends/'); const html = await response.text(); const doc = new DOMParser().parseFromString(html, 'text/html'); const uniqueUsernames = new Set(); doc.querySelectorAll( 'div.market_grid [href*="/userlookup/?user="]') .forEach(function (element) { uniqueUsernames.add(element.getAttribute( 'href').split('=')[1]); }); console.log("Friends List Synced"); return Array.from(uniqueUsernames); } catch (error) { console.error('Error fetching and extracting usernames:', error); return []; } } $(SyncFriends).on('click', async function () { console.log("clicked") const usernames = await syncFriendsList(); friendList = usernames; GM.setValue('friendList', friendList); console.log('Synced usernames:', usernames); }); function syncBlockedList() { if (window.location.href === 'https://www.grundos.cafe/block/') { const blockList = $('.block_list').find('span').map( function () { return $(this).text(); }).get(); GM.setValue('blockList', blockList); console.log('blockList stored:', blockList); } else { if (confirm( 'You can only do this from the Blocked Users page. Want to open it in a new tab?' )) { window.open('https://www.grundos.cafe/block/', '_blank'); } else { console.log('User declined. No blocked sync occured.'); } } } $(SyncBlocked).on('click', syncBlockedList); function syncGuildMembers() { if (/^https:\/\/www\.grundos\.cafe\/guilds\/guild\/.+\/members\//.test(window.location.href)) { const userName = /user=(.*?)"/g.exec(document.body.innerHTML)[1]; const guildIdentifier = window.location.href.match(/guild\/([^\/-]+)/)?.[1]; const guildName = $('.guild-header strong').eq(0).text(); const guildID = "guildID_" + guildIdentifier; const guildMembers = [...new Set($('div.member-grid [href*="/userlookup/?user="]') .map(function() { return $(this).attr('href').split('=')[1]; }) .filter(function(guildMember) { return guildMember !== userName; }) )]; GM.getValue('guildsList', {}).then(function(guildsList) { guildsList[guildID] = { 'guildName': guildName, 'guildMembers': guildMembers }; GM.setValue('guildsList', guildsList); }); } else { if (confirm('You can only do this from the Guild Members page. Want to open it in a new tab?')) { window.open('https://www.grundos.cafe/guilds/', '_blank'); } else { console.log('User declined. No action occurred.'); } } } $(SyncGuild).on('click', syncGuildMembers);