A rewrite of Poly+, my quality-of-life browser extension for Polytoria. Built entirely fresh using the WXT extension framework, Typescript, and with added better overall code quality.
extension
1import config from "@/utils/config.json";
2import { _favoritedPlaces } from "@/utils/storage";
3import { expireCache } from "@/utils/utilities";
4import * as apiTypes from "@/utils/api/types";
5const placeID = window.location.pathname.split('/')[2];
6
7/**
8 * Displays a row of user-selected places at the top of the user's dashboard.
9 */
10export async function favoritedPlaces() {
11 let placeIDs = await _favoritedPlaces.getValue();
12
13 const button = document.createElement('button');
14 button.classList.add('btn', 'btn-primary', 'btn-sm');
15 button.style.position = 'absolute';
16 button.style.top = '0';
17 button.style.right = '0';
18 button.style.margin = '4px';
19 button.style.fontSize = '1.3em';
20 button.innerHTML = `
21 <i class="fa-regular fa-star"></i>
22 `;
23
24 const update = function() {
25 button.classList.value = 'btn btn-primary btn-sm';
26 button.disabled = false;
27 if (placeIDs.indexOf(placeID) == -1) {
28 // Not Pinned
29 if (placeIDs.length >= config.limits.favoritedPlaces) {
30 button.disabled = true;
31 }
32 button.children[0].classList.value = 'fa-regular fa-star';
33 } else {
34 // Pinned
35 button.children[0].classList.value = 'fa-duotone fa-star';
36 }
37 };
38
39 button.addEventListener('mouseenter', function() {
40 if (placeIDs.indexOf(placeID) != -1) {
41 button.classList.add('btn-danger');
42 button.classList.remove('btn-primary');
43 button.children[0].classList.add('fa-star-half-stroke');
44 button.children[0].classList.remove('fa-star');
45 };
46 });
47
48 button.addEventListener('mouseleave', function() {
49 if (placeIDs.indexOf(placeID) != -1) {
50 button.classList.add('btn-primary');
51 button.classList.remove('btn-danger');
52 button.children[0].classList.add('fa-star');
53 button.children[0].classList.remove('fa-star-half-stroke');
54 };
55 });
56
57 update();
58 document.querySelector('h1.my-0')!.parentElement!.appendChild(button);
59
60 button.addEventListener('click', function() {
61 if (placeIDs.indexOf(placeID) == -1) {
62 placeIDs.push(placeID);
63 } else {
64 placeIDs.splice(placeIDs.indexOf(placeID), 1);
65 }
66
67 expireCache('favoritedPlaces');
68 _favoritedPlaces.setValue(placeIDs);
69 update();
70 });
71
72 storage.watch<Array<string>>('sync:favoritedPlaces', (value, previous) => {
73 placeIDs = value!;
74 });
75};
76
77/**
78 * Displays the approximated amount of revenue generated from a certain place, based off the unique visits & any gamepass sales (taking into account the creator's current membership tax)
79 */
80export async function approxPlaceRevenue() {
81 const round = (number: number) => Math.round(number / config.economy.visitorPayouts.visitors) * config.economy.visitorPayouts.visitors;
82 const infoCard = document.querySelector('.card-body .row:has(.fa-calendar)')!;
83
84 const key = document.createElement('li');
85 const value = document.createElement('li');
86
87 key.innerHTML = 'Revenue:';
88 value.innerHTML = '...';
89 value.classList.add(config.api.enabled ? 'text-success' : 'text-muted');
90
91 infoCard.children[0].appendChild(key);
92 infoCard.children[1].appendChild(value);
93
94 const revenue = await pullKVCache(
95 "placeRevenue",
96 placeID,
97 async () => {
98 if (!config.api.enabled) return "disabled";
99
100 const place: apiTypes.placeApiSchema = (await (await fetch(config.api.urls.public + 'places/' + placeID)).json());
101 const store: apiTypes.gamepassesApiSchema = (await (await fetch(config.api.urls.public + 'places/' + placeID + '/gamepasses')).json());
102 const creator: apiTypes.userApiSchema = (await (await fetch(config.api.urls.public + 'users/' + place.creator.id)).json());
103
104 const visitorPayout = round(place.uniqueVisits) / config.economy.visitorPayouts.visitors;
105 let gamepassRevenue = 0;
106
107 for (const gamepass of store.gamepasses) {
108 const price = Math.floor(gamepass.asset.price - (gamepass.asset.price * config.economy.membershipTax[creator.membershipType]))
109 gamepassRevenue += price * gamepass.asset.sales;
110 };
111
112 return visitorPayout + gamepassRevenue;
113 },
114 300000,
115 false
116 );
117
118 if (revenue == "disabled") {
119 value.innerText = 'Sorry, this feature is currently unavailable! Check back later!';
120 throw new Error("[Poly+] API is disabled, cancelling approx. place revenue loading..");
121 };
122
123 value.innerHTML = '<i class="pi pi-brick me-2"></i> ~' + revenue.toLocaleString();
124};