[GC] Organize SW Results

Blocked users can be synced but do not actually change anything in the SW results yet.

当前为 2025-01-27 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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