const ItemID = window.location.pathname.split('/')[2] const ItemType = document.querySelector('.row .badge').innerHTML console.log(ItemType) var Settings; var ItemWishlist; var PurchaseBtn; var WishlistBtn; var ItemOwned; var InitialOwners; var OwnerPagesFetched = 0; var Utilities; (async () => { Utilities = await import(chrome.runtime.getURL('resources/utils.js')); Utilities = Utilities.default chrome.storage.sync.get(['PolyPlus_Settings'], async function(result){ Settings = result.PolyPlus_Settings || {} PurchaseBtn = document.querySelector('.btn[onclick^="buy"]') if (PurchaseBtn === null) { PurchaseBtn = document.querySelector('.btn#purchase-button') } ItemOwned = (PurchaseBtn.innerText === ' Item owned' || document.querySelector('.btn[onclick="sellItem()"]') !== null) if (PurchaseBtn.getAttribute('data-seller-name')) { PurchaseBtn.setAttribute('data-bs-toggle', 'tooltip') PurchaseBtn.setAttribute('data-bs-title', 'Sold by ' + PurchaseBtn.getAttribute('data-seller-name')) Utilities.InjectResource('registerTooltips') } if (Settings.IRLPriceWithCurrency.Enabled === true && ItemOwned === false) { IRLPrice() } if (Settings.ItemWishlistOn === true) { HandleItemWishlist() } if (Settings.TryOnItemsOn === true && (Utilities.MeshTypes.indexOf(ItemType.toLowerCase()) !== -1 || Utilities.TextureTypes.indexOf(ItemType.toLowerCase()) !== -1)) { TryOnItems() } if (Settings.ReplaceItemSalesOn === true) { const Sales = document.querySelectorAll('.col:has(h6):has(h3.small)')[2] if (Sales.children[1].innerText === '0') { InitialOwners = (await (await fetch('https://api.polytoria.com/v1/store/' + ItemID + '/owners?limit=100')).json()) Sales.children[0].innerText = 'Owners' Sales.children[1].innerText = Owners.total.toLocaleString() } } if (document.getElementById('resellers') !== null) { if (Settings.HoardersList.Enabled === true) { console.log(parseInt(Settings.HoardersList.MinCopies)) HoardersList(parseInt(Settings.HoardersList.MinCopies), Settings.HoardersList.AvatarsEnabled) } } else if (document.getElementById('timer') && /\d/.test(document.getElementById('timer').innerText)) { CheckOwner() } }) })(); chrome.storage.onChanged.addListener(function(changes, namespace) { if ('PolyPlus_ItemWishlist' in changes) { chrome.storage.sync.get(['PolyPlus_ItemWishlist'], function(result) { ItemWishlist = result.PolyPlus_ItemWishlist || []; if (Array.isArray(ItemWishlist) && ItemWishlist.includes(parseInt(ItemID))) { WishlistBtn.classList = 'btn btn-danger btn-sm' WishlistBtn.innerHTML = ` Un-Wishlist Item ` } else { if (!(ItemWishlist.length === 25)) { WishlistBtn.removeAttribute('disabled') WishlistBtn.classList = 'btn btn-warning btn-sm' WishlistBtn.innerHTML = ` Wishlist Item ` } else { WishlistBtn.setAttribute('disabled', true) WishlistBtn.classList = 'btn btn-warning btn-sm' WishlistBtn.innerHTML = ` Wishlist Item ` } } }); } }); async function IRLPrice() { const Price = PurchaseBtn.getAttribute('data-price') if (Price === null || Price === "0") { return } const Span = document.createElement('span') Span.classList = 'text-muted polyplus-own-tag' Span.style.fontSize = '0.7rem' Span.style.fontWeight = 'normal' const IRLResult = await Utilities.CalculateIRL(Price, Settings.IRLPriceWithCurrency.Currency) Span.innerText = "($" + IRLResult.result + " " + IRLResult.display + ")" PurchaseBtn.appendChild(Span) } function HandleItemWishlist() { const DescriptionText = document.querySelector('.mcard .card-body:has(p)') WishlistBtn = document.createElement('button') chrome.storage.sync.get(['PolyPlus_ItemWishlist'], function(result){ ItemWishlist = result.PolyPlus_ItemWishlist || []; if (ItemOwned === true) { if (ItemWishlist.includes(parseInt(ItemID))) { ItemWishlist.splice(ItemWishlist.indexOf(parseInt(ItemID)), 1) chrome.storage.sync.set({'PolyPlus_ItemWishlist': ItemWishlist, arrayOrder: true}); } return } if (ItemOwned === true) { return } else if (ItemOwned === true && ItemWishlist.includes(parseInt(ItemID))) { ItemWishlist.splice(ItemWishlist.indexOf(parseInt(ItemID)), 1) return } if (ItemWishlist.includes(parseInt(ItemID))) { WishlistBtn.classList = 'btn btn-danger btn-sm' WishlistBtn.innerHTML = ` Un-Wishlist Item ` } else { WishlistBtn.classList = 'btn btn-warning btn-sm' WishlistBtn.innerHTML = ` Wishlist Item ` } WishlistBtn.addEventListener('click', function(){ WishlistBtn.setAttribute('disabled', true) chrome.storage.sync.get(['PolyPlus_ItemWishlist'], function(result){ ItemWishlist = result.PolyPlus_ItemWishlist || []; let i = ItemWishlist.indexOf(parseInt(ItemID)) if (i !== -1) { ItemWishlist.splice(i, 1) WishlistBtn.classList = 'btn btn-warning btn-sm' WishlistBtn.innerHTML = ` Wishlist Item ` } else { ItemWishlist.push(parseInt(ItemID)) WishlistBtn.classList = 'btn btn-danger btn-sm' WishlistBtn.innerHTML = ` Un-Wishlist Item ` } chrome.storage.sync.set({'PolyPlus_ItemWishlist': ItemWishlist, arrayOrder: true}, function() { setTimeout(function() { WishlistBtn.removeAttribute('disabled') }, 1250) }); }); }); DescriptionText.appendChild(document.createElement('br')) DescriptionText.appendChild(WishlistBtn) }); } function TryOnItems() { const Avatar = { "useCharacter": true, "items": [], "shirt": "https://c0.ptacdn.com/assets/uWrrnFGwgNN5W171vqYTWY7E639rKiXK.png", "pants": "https://c0.ptacdn.com/assets/HD6TFdXD8CaflRNmd84VCNyNsmTB0SH3.png", "headColor": "#e0e0e0", "torsoColor": "#e0e0e0", "leftArmColor": "#e0e0e0", "rightArmColor": "#e0e0e0", "leftLegColor": "#e0e0e0", "rightLegColor": "#e0e0e0" } let AssetType = document.querySelector('.px-4.px-lg-0.text-muted.text-uppercase.mb-3 .badge').innerHTML const ItemThumbnail = document.getElementsByClassName('store-thumbnail')[0] //const IFrame = document.getElementsByClassName('store-thumbnail-3d')[0] const TryIFrame = document.createElement('iframe') TryIFrame.style = 'width: 100%; height: auto; aspect-ratio: 1; border-radius: 20px;' const TryOnBtn = document.createElement('button') TryOnBtn.classList = 'btn btn-warning' TryOnBtn.style = 'position: absolute; bottom: 60px; right: 10px;' if (document.getElementsByClassName('3dviewtoggler')[0] === undefined) { TryOnBtn.style.bottom = '15px' } //TryOnBtn.setAttribute('data-bs-toggle', 'tooltip') //TryOnBtn.setAttribute('data-bs-title', 'Try this item on your avatar') TryOnBtn.innerHTML = '' TryOnBtn.addEventListener('click', function (){ fetch("https://api.polytoria.com/v1/users/" + JSON.parse(window.localStorage.getItem('p+account_info')).ID + "/avatar") .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { data.assets.forEach(item => { switch (item.type) { case 'hat': Avatar.items[Avatar.items.length] = item.path || '' break case 'face': Avatar.face = item.path || '' break case 'tool': Avatar.tool = item.path || '' break case 'shirt': Avatar.shirt = item.path || '' break case 'pants': Avatar.pants = item.path || '' break } }); Avatar.headColor = "#" + data.colors.head Avatar.torsoColor = "#" + data.colors.torso Avatar.leftArmColor = "#" + data.colors.leftArm Avatar.rightArmColor = "#" + data.colors.rightArm Avatar.leftLegColor = "#" + data.colors.leftLeg Avatar.rightLegColor = "#" + data.colors.rightLeg if (Utilities.MeshTypes.indexOf(AssetType.toLowerCase()) !== -1) { fetch("https://api.polytoria.com/v1/assets/serve-mesh/:id".replace(':id', window.location.pathname.split('/')[2])) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { if (ItemType === 'tool') { Avatar.tool = data.url } else { Avatar.items.push(data.url) } console.log(Avatar) TryIFrame.src = 'https://polytoria.com/ptstatic/itemview/#' + btoa(encodeURIComponent(JSON.stringify(Avatar))) }) .catch(error => { console.error('Fetch error:', error); }); } else if (Utilities.TextureTypes.indexOf(AssetType.toLowerCase()) !== -1) { fetch("https://api.polytoria.com/v1/assets/serve/:id/Asset".replace(':id', window.location.pathname.split('/')[2])) .then(response => { if (!response.ok) { throw new Error('Network response was not ok'); } return response.json(); }) .then(data => { switch (AssetType) { case 'Shirt': console.log('IS SHIRT') Avatar.shirt = data.url break case 'Pants': console.log('IS PANTS') Avatar.pants = data.url break case 'Face': console.log('IS FACE') Avatar.face = data.url break } TryIFrame.src = 'https://polytoria.com/ptstatic/itemview/#' + btoa(encodeURIComponent(JSON.stringify(Avatar))) }) .catch(error => { console.error('Fetch error:', error); }); } }) .catch(error => { console.error('Fetch error:', error); }); TryOnModal.showModal() }); let TryOnModal = document.createElement('dialog') TryOnModal.classList = 'polyplus-modal' TryOnModal.setAttribute('style', 'width: 450px; border: 1px solid #484848; background-color: #181818; border-radius: 20px; overflow: hidden;') TryOnModal.innerHTML = `
Preview
Try this avatar on your avatar before purchasing it!
` document.body.prepend(TryOnModal) ItemThumbnail.parentElement.appendChild(TryOnBtn) TryOnModal.children[1].prepend(TryIFrame) //Utilities.InjectResource('registerTooltips') } async function HoardersList(min, avatars) { let Page = 0 let Tabs = document.getElementById('store-tabs') const Tab = document.createElement('li') Tab.classList = 'nav-item' Tab.innerHTML = ` Hoarders ` Tabs.appendChild(Tab) const TabContent = document.createElement('div') TabContent.classList = 'd-none' TabContent.innerHTML = ` loading... (this may take a few seconds) ` document.getElementById('owners').parentElement.appendChild(TabContent) // Add tab logic Array.from(Tabs.children).forEach(tab => { tab.addEventListener('click', function() { if (tab === Tab) { Array.from(Tabs.children).forEach(tab => {tab.children[0].classList.remove('active')}) Array.from(document.getElementById('owners').parentElement.children).forEach(tab => {tab.classList.add('d-none')}) tab.children[0].classList.add('active') TabContent.classList.remove('d-none') } }) }) let Fetched = false Tab.addEventListener('click', async function(){ if (Fetched === true) { return } Fetched = true const Owners = [] if (InitialOwners === undefined) { InitialOwners = (await (await fetch('https://api.polytoria.com/v1/store/' + ItemID + '/owners?limit=100')).json()) } Owners.push(...InitialOwners.inventories) // Get owners (up to 300, if needed) if (InitialOwners.pages > 3) { InitialOwners.pages = 3 } if (InitialOwners.pages > 1 && OwnerPagesFetched < InitialOwners.pages) { for (let i = 1; i < InitialOwners.pages; i++) { const PageResult = (await (await fetch('https://api.polytoria.com/v1/store/' + ItemID + '/owners?limit=100&page=' + (i+1))).json()).inventories console.log(PageResult) Owners.push(...PageResult) } } const Formatted = {} // Count copies & store serials of owners for (let owner of Owners) { if (Formatted[owner.user.id] !== undefined) { Formatted[owner.user.id].copies++ Formatted[owner.user.id].serials.push(owner.serial) } else { Formatted[owner.user.id] = { user: owner.user, copies: 1, serials: [owner.serial] } } } let Hoarders = await new Promise(async (resolve, reject) => { const Sorted = Object.values(Formatted).filter((x, index) => x.copies >= min).sort((a, b) => b.copies - a.copies) if (avatars === true) { for (let hoarder of Sorted) { const Avatar = (await (await fetch('https://api.polytoria.com/v1/users/' + hoarder.user.id)).json()).thumbnail.icon; hoarder.user.avatar = Avatar; } } resolve(Sorted) }) let AmountOfHoarders = Hoarders.length // Break hoarders into groups of 4 let Groups = [] while (Hoarders.length > 0) { Groups.push(Hoarders.splice(0, 4)) } TabContent.innerHTML = `
${ (Groups[Page] !== undefined) ? Groups[Page].map((x) => `
${ (avatars === true) ? `
${x.user.username}
` : '' }
${x.user.username}
${x.copies} Copies
`).join('') : `

No hoarders

This item is fresh and doesn't have any hoarders yet! Come back later!

`}
` Utilities.InjectResource('registerTooltips') const Container = document.getElementById('p+hoarders-container') // Pagination is annoying const First = document.getElementById('p+hoarders-first-pg') const Prev = document.getElementById('p+hoarders-prev-pg') const Current = document.getElementById('p+hoarders-current-pg') const Next = document.getElementById('p+hoarders-next-pg') const Last = document.getElementById('p+hoarders-last-pg') const MinCopies = document.getElementById('p+hoarders-min-copies') MinCopies.selectedIndex = Array.from(MinCopies.children).indexOf(MinCopies.querySelector(`option[value="${min}"]`)) if (Page > 0) { Prev.parentElement.classList.remove('disabled') First.parentElement.classList.remove('disabled') } else { Prev.parentElement.classList.add('disabled') First.parentElement.classList.add('disabled') } if (Page < Groups.length-1) { Next.parentElement.classList.remove('disabled') Last.parentElement.classList.remove('disabled') } else { Next.parentElement.classList.add('disabled') Last.parentElement.classList.add('disabled') } First.addEventListener('click', function() { if (Page > 0) { Page = 0 UpdateHoardersList() } }) Prev.addEventListener('click', function() { if (Page > 0) { Page-- UpdateHoardersList() } }) Next.addEventListener('click', function() { if (Page < Groups.length-1) { Page++ UpdateHoardersList() } }) Last.addEventListener('click', function() { if (Page < Groups.length-1) { Page = Groups.length-1 UpdateHoardersList() } }) MinCopies.addEventListener('change', function(){ Page = 0 min = parseInt(MinCopies.options[MinCopies.selectedIndex].value) Hoarders = Object.values(Formatted).filter((x, index) => x.copies >= min).sort((a, b) => b.copies - a.copies) AmountOfHoarders = Hoarders.length Groups = [] while (Hoarders.length > 0) { Groups.push(Hoarders.splice(0, 4)) } UpdateHoardersList() }) const UpdateHoardersList = function() { console.log(Hoarders, AmountOfHoarders, Groups) Current.innerText = Page+1 if (Groups[Page] !== undefined) { Container.innerHTML = Groups[Page].map((x) => `
${ (avatars === true) ? `
${x.user.username}
` : '' }
${x.user.username}
${x.copies} Copies
`).join('') Utilities.InjectResource('registerTooltips') } else { Container.innerHTML = `

No hoarders

This item is fresh and doesn't have any hoarders yet! Come back later!

` MinCopies.disabled = true } if (Page > 0) { Prev.parentElement.classList.remove('disabled') First.parentElement.classList.remove('disabled') } else { Prev.parentElement.classList.add('disabled') First.parentElement.classList.add('disabled') } if (Page < Groups.length-1) { Next.parentElement.classList.remove('disabled') Last.parentElement.classList.remove('disabled') } else { Next.parentElement.classList.add('disabled') Last.parentElement.classList.add('disabled') } } }) } function CheckOwner() { const ImageCard = document.querySelector('.card-body:has(.store-thumbnail)') const CheckOwnerDiv = document.createElement('div') CheckOwnerDiv.classList = 'mt-3 d-none' CheckOwnerDiv.innerHTML = `
... ` ImageCard.appendChild(CheckOwnerDiv) const ToggleButton = document.createElement('button') ToggleButton.classList = 'btn btn-dark' ToggleButton.style = 'position: absolute; bottom: 15px; left: 10px;' //ToggleButton.setAttribute('data-bs-toggle', 'tooltip') //ToggleButton.setAttribute('data-bs-title', 'Quickly check if someone owns this item') ToggleButton.innerHTML = '' ImageCard.children[0].prepend(ToggleButton) const UsernameInput = CheckOwnerDiv.getElementsByTagName('input')[0] const CheckButton = CheckOwnerDiv.getElementsByTagName('button')[0] const ResultText = CheckOwnerDiv.getElementsByTagName('b')[0] ToggleButton.addEventListener('click', function(){ if (CheckOwnerDiv.classList.contains('d-none')) { ResultText.classList = '' ResultText.innerHTML = ' ...' CheckOwnerDiv.classList.remove('d-none') } else { CheckOwnerDiv.classList.add('d-none') } }) UsernameInput.addEventListener('update', function(){ ResultText.classList = '' ResultText.innerHTML = ' ...' }) CheckButton.addEventListener('click', async function(){ const Username = UsernameInput.value if (Username.trim() === "") { ResultText.classList = '' ResultText.innerHTML = ' ...' return } const UserID = (await (await fetch('https://api.polytoria.com/v1/users/find?username=' + Username)).json()).id if (UserID !== undefined) { const Owns = (await (await fetch('https://api.polytoria.com/v1/store/' + ItemID + '/owner?userID=' + UserID)).json()) if (Owns.owned === true) { ResultText.classList = 'text-success' ResultText.innerHTML = ' ' + Username + ' owns #' + Owns.inventory.serial + ' of ' + document.getElementsByTagName('h1')[0].innerText + '".' } else { ResultText.classList = 'text-danger' ResultText.innerHTML = ' ' + Username + ' does not own "' + document.getElementsByTagName('h1')[0].innerText + '".' } } else { ResultText.classList = 'text-warning' ResultText.innerHTML = ' No user found under the username "' + Username + '".' } }) }