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

feat: API usage config JSON toggle + finished membership themes feature

Index 17ad8e53 66863afe

+23 -5
entrypoints/home.content.ts
···
</div>
`;
+
const card: HTMLElement = container.getElementsByClassName('scrollFadeContainer')[0] as HTMLElement;
const column = document.getElementsByClassName('col-lg-8')[0];
+
if (document.getElementsByClassName('home-event-container')[0] === undefined) {
column.insertBefore(container, column.children[0]);
} else {
column.insertBefore(container, column.children[1]);
-
}
+
};
-
const placeData: Array<placeApiSchema> = await pullCache(
+
const placeData: Array<placeApiSchema> | "disabled" = await pullCache(
'favoritedPlaces',
async () => await api.batch('public', 'places/', places),
300000,
-
false
+
true
);
-
const card = container.getElementsByClassName('scrollFadeContainer')[0]
+
if (placeData == "disabled") {
+
console.error('[Poly+] API is disabled, cancelling favorited places loading..');
+
card.innerHTML = `
+
<div class="text-center p-2">
+
<img src="${ browser.runtime.getURL('/svgs/error.svg') }" width="100" height="100">
+
<p class="text-muted mb-0">Sorry! This feature is currently unavailable. Please check back later!</p>
+
</div>
+
`;
+
+
return;
+
};
+
for (let i = 0; i < places.length; i++) {
const id = places.toSorted((a, b) => parseInt(b) - parseInt(a))[i]
const details = placeData[parseInt(id)]
···
'bestFriends',
async () => await api.batch('public', 'users/', friends),
300000,
-
false
+
true
);
+
+
if (userData == "disabled") {
+
console.error('[Poly+] API is disabled, cancelling best friends loading..');
+
return;
+
};
for (const id of friends) {
if (!userData[id]) {
+9 -3
entrypoints/preferences-handler.ts
···
select.appendChild(option);
};
+
select.addEventListener('change', function() {
+
document.getElementById('save')!.removeAttribute('disabled');
+
values[data.setting][subsetting.subsetting] = select.options[select.selectedIndex].value;
+
});
+
div.appendChild(select);
} else if (subsetting.type === 'check') {
const check = document.createElement('span');
···
</label>
`;
+
const checkbox = check.getElementsByClassName('form-check-input')[0] as HTMLInputElement;
+
checkbox.checked = values[data.setting][subsetting.subsetting];
+
check.getElementsByClassName('form-check-input')[0].addEventListener('change', () => {
document.getElementById('save')!.removeAttribute('disabled');
-
-
const state = !values[data.setting][subsetting.subsetting];
-
values[data.setting][subsetting.subsetting] = state;
+
values[data.setting][subsetting.subsetting] = checkbox.checked;
});
div.appendChild(check);
+4 -2
entrypoints/sitewide.content.ts
···
};
};
-
if (values.membershipThemes.enabled) membershipThemes(values.membershipThemes.themeId as "plus" | "plusDx");
+
if (values.membershipThemes.enabled) membershipThemes(values.membershipThemes.themeId as "plus" | "plusdx");
});
});
}
});
-
function membershipThemes(themeId: "plus" | "plusDx") {
+
function membershipThemes(themeId: "plus" | "plusdx") {
const navbar = document.querySelector('.navbar.navbar-expand-lg.navbar-light.bg-navbar.nav-topbar')!;
const sidebar = document.querySelector('.d-flex.flex-column.flex-shrink-0.bg-sidebar.nav-sidebar')!;
navbar.classList.add('navbar-' + themeId);
sidebar.classList.add('sidebar-' + themeId);
+
+
sidebar.getElementsByTagName('img')[0].src = browser.runtime.getURL(`/svgs/${themeId}.svg` as `/svgs/plus.svg` | `/svgs/plusdx.svg`);
};
+2 -2
public/preferences.json
···
},
{
"name": "Free Membership Themes",
-
"desc": "Ever want the fancy membership themes for completely free? Well now you can apply them site-wide!",
+
"desc": "Ever want the fancy membership themes for completely free? Well now you can apply them on the site-wide navigation without paying a dime!",
"setting": "membershipThemes",
"config": [
{
···
"subsetting": "themeId",
"values": {
"plus": "Plus",
-
"plusDX": "Plus Deluxe"
+
"plusdx": "Plus Deluxe"
}
}
],
+173
public/svgs/error.svg
···
+
+
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="none" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512">
+
<defs>
+
<image id="Bitmap_1" x="0" y="0" width="510" height="575" xlink:href="./images/Bitmap_1.png"/>
+
+
<g id="Layer6_0_FILL">
+
<path fill="#999999" stroke="none" d="
+
M 332.3 227.15
+
Q 332 216.85 327.3 207.8 325.05 203.45 320.9 200.4 307.9 190.65 291.4 188.5 278.6 186.85 265.75 187.15 265.6 187.15 265.45 187.15 265.3 187.15 265.15 187.15 252.25 186.85 239.5 188.5 224.35 190.45 212.15 198.85 211.05 199.6 210 200.4 205.85 203.45 203.6 207.8 198.9 216.85 198.6 227.15 198.4 234.7 198 242.3 197.289453125 255.5501953125 197.15 268.75 197.106640625 274.1291015625 197.15 279.5 197.25 292.05 200.25 304.2 203.9 314.5 212.15 320.65 212.35 320.8 212.6 320.95 216.35 323.6 221 325.45 228.4 328.3 236.15 329.95 246.55 332.15 257.55 332.1 261.35 332.05 265.15 332.15 265.3 332.15 265.45 332.15 265.6 332.15 265.75 332.15 269.55 332.05 273.35 332.1 284.4 332.15 294.85 329.95 295.2 329.9 295.55 329.8 302.85 328.15 309.9 325.45 325.3 319.4 330.65 304.2 333.65 292.05 333.75 279.5 333.793359375 274.1291015625 333.75 268.75 333.610546875 255.5501953125 332.9 242.3 332.5 234.7 332.3 227.15
+
M 294.65 245.15
+
Q 294.6638671875 245.1359375 294.65 245.1 293.3052734375 242.2865234375 293.3 238.55 293.3046875 236.3205078125 293.4 235.45 293.5369140625 234.333203125 294.2 232.95 295.1150390625 230.573828125 298.25 230.85
+
L 298.3 230.85
+
Q 300.1451171875 230.978515625 301.85 231.65 301.888671875 231.6849609375 301.9 231.7 304.3708984375 232.64921875 304.75 234.1 304.7767578125 234.1779296875 304.8 234.25 305.4962890625 236.417578125 305.5 239.1 305.4962890625 242.9103515625 304 245.6
+
L 304 245.6
+
Q 302.0779296875 249.246484375 299.2 248.75 296.5388671875 248.7609375 294.65 245.15
+
M 280.3 215.25
+
Q 280.291015625 216.109375 279.7 216.7 271.2767578125 224.8314453125 264.95 223.85 262.334765625 223.5755859375 260.05 221.8 259.425390625 221.316015625 259.3 220.5 259.2185546875 219.68046875 259.7 219 260.2330078125 218.37421875 261.05 218.25 261.8681640625 218.16953125 262.5 218.65 263.8650390625 219.72421875 265.4 219.9 270.2212890625 220.2703125 276.9 213.8 277.4982421875 213.231640625 278.3 213.25 279.148828125 213.25859375 279.7 213.85 280.3078125 214.4478515625 280.3 215.25
+
M 277.8 234.5
+
L 277.8 234.55
+
Q 277.9966796875 235.8037109375 278 237.2 278.00078125 241.0296875 276.5 243.65
+
L 276.5 243.65
+
Q 274.595703125 247.2513671875 271.75 246.85 269.05625 246.8943359375 267.15 243.25 267.1638671875 243.2359375 267.15 243.2 265.8052734375 240.3865234375 265.8 236.65 265.8056640625 235.580859375 265.9 234.6
+
L 265.9 234.6
+
Q 266.1484375 232.7376953125 266.7 231.2
+
L 266.7 231.3
+
Q 267.1833984375 229.867578125 268.1 229.55 268.464453125 229.2458984375 271 229.4 272.703515625 229.5 273.9 229.6 276.8810546875 229.857421875 276.85 231.2 277.5357421875 232.7498046875 277.8 234.5
+
M 270.5 267.75
+
Q 272.33984375 267.89453125 274 268.75 277.459375 270.494921875 280.25 275.3 282.9083984375 279.4583984375 289.25 277.8 294.87265625 276.3974609375 298 279 301.1666015625 281.2669921875 301.8 287.25 301.9431640625 288.2943359375 301.3 289.1 300.651171875 289.909765625 299.6 290 298.6048828125 290.144140625 297.8 289.5 296.991015625 288.8517578125 296.85 287.8 296.4828125 284.3794921875 294.9 282.95 293.3314453125 281.9515625 290.5 282.65 280.0865234375 285.3427734375 275.95 277.8 273.3072265625 273.2583984375 270 272.7
+
L 269.95 272.7
+
Q 267.228515625 272.8138671875 265.05 278 264.6513671875 278.965234375 263.7 279.35 262.751171875 279.7478515625 261.8 279.35 260.84453125 278.9517578125 260.45 278 260.0525390625 277.04140625 260.45 276.05 262.699609375 270.6890625 265.65 268.75 267.8849609375 267.30546875 270.5 267.75 Z"/>
+
</g>
+
+
<g id="Layer5_0_FILL">
+
<path fill="#999999" stroke="none" d="
+
M 158.3 350.4
+
L 157.7 350.1 152.85 434.95 347.55 434.95 353.45 333.4 191 315.95 158.95 336.8 158.3 350.4 Z"/>
+
</g>
+
+
<g id="Layer4_0_FILL">
+
<path fill="#999999" stroke="none" d="
+
M 253.6 258.15
+
Q 255.5 253 255.15 249.7 255.15 248.85 254.75 248.3 254.4 247.95 253.85 247.85 253.25 247.8 252.85 248.1 252.7767578125 248.1533203125 252.7 248.2 252.6578125 248.180859375 252.6 248.15
+
L 251.8 247.9
+
Q 251.35 247.65 251.1 247.6 250.45 247.35 249.75 247.6 249.05 247.85 248.7 248.45 248.35 249 248.45 249.75 248.5 250.45 249 250.95 249.4 251.35 249.4 251.4 249.5 251.65 249.4 251.85 249.2 253.7 248.7 255.85
+
L 248 258.8
+
Q 247.7330078125 259.9123046875 247.85 260.45 247.363671875 260.5955078125 246.75 260.65 246 259.55 245.35 257.85
+
L 245.05 256.55
+
Q 244.95 255.95 244.95 254.7
+
L 245 250.65
+
Q 245.15 249.8 245.1 249.6 245 248.45 243.9 248.2 242.85 247.95 242.2 248.95 241.85 249.55 241.95 251 242 252.2 241.95 254.55 241.9 256.7 242.25 258.1 242.4 258.75 242.85 260 243.3 261.25 243.55 261.65
+
L 244.35 262.7
+
Q 245.15 263.4 245.5 263.5 246.05 263.75 246.95 263.75 248.7 263.65 250.05 262.95 251.15 262.45 251.85 261.6 252.4 261 252.75 260.25 253.05 259.7 253.6 258.15
+
M 154.25 281.15
+
L 94.8 293.75
+
Q 53.05 350.25 32.75 429.9 32.05 432.4 31.45 434.95
+
L 152.2 434.95
+
Q 152.85 432.4 153.55 429.9 166.8 382.35 194.2 342.6 194.3 342.45 194.4 342.3 205.2 342.6 154.25 281.15
+
M 450.05 143.4
+
Q 448.35 143.4 446.5 143.75
+
L 441.25 132.7 428.85 138.5 434.45 150.25
+
Q 433.6 151.15 432.8 152.1
+
L 420.6 147.75 416.05 160.75 428.25 165
+
Q 428.25 166.8 428.4 168.5
+
L 419 172.9 424.9 185.5 434.35 181.05
+
Q 435.6 182.25 436.9 183.4
+
L 432.55 195.5 445.5 200.15 449.8 188
+
Q 451.05 188.05 452.3 187.9
+
L 457.8 199.6 470.2 193.75 464.95 182.6
+
Q 466.35 181.45 467.5 180.1
+
L 480.2 184.65 484.8 171.75 472.7 167.4
+
Q 472.9 165.05 472.5 162.85
+
L 484.15 157.25 478.3 145.05 466.65 150.45
+
Q 465.15 148.8 463.3 147.5
+
L 467.55 135.35 454.65 130.7 450.05 143.4
+
M 441.6 169.4
+
L 441.55 169.35
+
Q 440.25 165.95 441.5 162.4 442.8 158.65 446.45 156.9 450.2 155.15 453.95 156.55 457.7 157.9 459.45 161.4 459.5 161.4 459.45 161.5 461.15 165.15 459.85 168.9 458.55 172.65 454.8 174.45 451.15 176.15 447.3 174.8 443.8 173.55 442 170.3 442.05 170.2 441.95 170.2 441.9 170.05 441.9 169.9 441.75 169.8 441.75 169.75 441.65 169.6 441.65 169.55 441.6 169.5 441.6 169.4
+
M 389.65 189.4
+
L 369.25 197.65 377.4 217.65
+
Q 375.3 219.55 373.55 221.95
+
L 355.4 214.25 346.85 234.45 365.9 242.55
+
Q 365.8 244.55 366.05 246.5
+
L 346.8 254.35 355 274.7 374.25 266.8
+
Q 376 269 378.15 270.75
+
L 371.6 286.15 392.15 294.85 398.7 279.45
+
Q 401.5 279.7 404.1 279.5
+
L 411.95 298.75 432.3 290.4 424.6 271.25
+
Q 426.1 270.05 427.5 268.65
+
L 446.5 276.7 455.15 256.35 436.95 248.7
+
Q 437.35 245.9 437.3 243
+
L 457.3 234.9 449.1 214.55 429.9 222.3
+
Q 427.65 219.35 424.8 216.95
+
L 432.8 198 412.8 189.5 404.8 208.5
+
Q 401.15 208.05 397.45 208.6
+
L 389.65 189.4
+
M 407.65 229.2
+
Q 407.8 229.25 407.95 229.3 413.8 231.8 416.05 237.75 418.6 243.75 416.05 249.65 413.55 255.75 407.45 258.2 401.9 260.4 396.35 258.4 396.25 258.4 396.2 258.35 395.95 258.35 395.75 258.2 395.6 258.15 395.45 258.1 395.3 258.05 395.05 257.9 395 257.85 394.95 257.85
+
L 394.9 257.8
+
Q 389.6 255.2 387.35 249.5 384.85 243.6 387.45 237.65 390 231.6 395.95 229.15 401.8 226.8 407.65 229.2
+
M 338.65 70.6
+
L 340.15 95.5
+
Q 335.9 96.95 332.15 99.5
+
L 313.45 83 295.95 102.85 315.45 120.1
+
Q 314.2 123.3 313.6 126.8
+
L 289.85 128.2 291.5 154.75 316.3 153.25
+
Q 317.4 155.4 318.65 157.4
+
L 302 176.1 322 193.75 338.4 174.95
+
Q 341.55 176.25 344.85 177.05
+
L 346.05 197.25 372.85 195.6 371.75 175.45
+
Q 374.8 174.15 377.6 172.5
+
L 396.35 189.15 413.85 169.25 395.2 152.65
+
Q 396.2 150.6 396.95 148.2
+
L 421.9 146.65 420.3 120.15 396.45 121.65
+
Q 395.4 118.3 393.8 115.3
+
L 411 95.8 391.2 78.25 374.65 96.9
+
Q 370.65 94.85 366.25 93.95
+
L 364.8 69.1 338.65 70.6
+
M 368.05 121.1
+
Q 373.9 126.15 374.4 133.9 374.85 141.8 369.75 147.75 367.2595703125 150.441796875 364.25 152 361.278125 153.527734375 357.8 153.95 357.75 153.95 357.65 153.95 357.4 154.05 357.05 154 356.9 154.05 356.7 154.05 356.5 154.05 356.2 154.05 356.15 154.1 356 154.1
+
L 355.95 154.05
+
Q 348.8 154.05 343.3 149.3 337.5 144.1 337 136.35 336.6 128.5 341.65 122.65 346.8 116.85 354.3 116.2 354.55 116.2 354.75 116.2 359.96484375 115.92734375 364.25 118.3 366.2513671875 119.412890625 368.05 121.1 Z"/>
+
</g>
+
+
<g id="Layer0_0_FILL">
+
<path fill="#999999" stroke="none" d="
+
M 421.7 315
+
L 355.35 302.3 320.25 334.4
+
Q 320.75 341.7 321.55 348.95 325.95 391 339.15 429.9 340 432.45 340.9 434.95
+
L 465.05 434.95
+
Q 463.35 432.45 461.75 429.9 451.9 414.6 444.2 398.75 423.65 356.05 421.7 315 Z"/>
+
</g>
+
+
<font horiz-adv-x="2048">
+
<!-- Font Name: Tw Cen MT
+
Vendor ID: MONO
+
Digitized data copyright The Monotype Corporation 1991-1997. All rights reserved. Twentieth Century™ is a trademark of The Monotype Corporation which may be registered in certain jurisdictions.
+
URL for more Information: http://www.adobe.com/go/font_vendor_id?ID=MONO&Name=Tw%20Cen%20MT&PSName=TwCenMT-Regular&applanguage=en_US-->
+
<font-face font-family="Tw_Cen_MT_Regular" units-per-em="2048" ascent="1753" descent="477"/>
+
+
<glyph unicode="." horiz-adv-x="449" d="
+
M 86 117
+
Q 86 172 126 212 165 252 221 252 276 252 316 212 356 172 356 117 356 61 317 21 277 -18 221 -18 165 -18 126 21 86 60 86 117 Z"/>
+
</font>
+
</defs>
+
+
<g transform="matrix( 1, 0, 0, 1, 705,252) ">
+
<use xlink:href="#Bitmap_1"/>
+
</g>
+
+
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
+
<use xlink:href="#Layer6_0_FILL"/>
+
</g>
+
+
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
+
<use xlink:href="#Layer5_0_FILL"/>
+
</g>
+
+
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
+
<use xlink:href="#Layer4_0_FILL"/>
+
</g>
+
+
<g transform="matrix( 9.521408081054688, -0.583251953125, 0.583251953125, 9.521408081054688, 109.65,165.5) ">
+
<clipPath id="Mask_Mask_1">
+
<rect x="-2" y="-2" width="12.15" height="17.8" fill="#FFFFFF" stroke="none"/>
+
</clipPath>
+
+
<text clip-path="url(#Mask_Mask_1)" writing-mode="lr"><tspan x="0" y="11" baseline-shift="0%" kerning="auto" font-family="Tw_Cen_MT_Regular" font-size="12" fill="#999999" xml:space="preserve">...</tspan></text>
+
</g>
+
+
<g transform="matrix( 1, 0, 0, 1, 0,0) ">
+
<use xlink:href="#Layer0_0_FILL"/>
+
</g>
+
</svg>
+12
utils/api.ts
···
ids: string[],
headers?: Record<string, any>
): Promise<any> {
+
if (!config.api.enabled) {
+
return "disabled"
+
};
+
if (!headers) headers = {};
const res: Record<string, any> = {};
···
startPage: number,
endingPage?: number
): Promise<any> {
+
if (!config.api.enabled) {
+
return "disabled"
+
};
+
let res: Array<any> = [];
const firstPage: { [key: string]: any } = await (await fetch(config.api.urls[type] + path + 1)).json();
···
};
export async function batchAction(path: string, headers: Array<Record<string, any>>) {
+
if (!config.api.enabled) {
+
return "disabled"
+
};
+
for (const request of headers) {
fetch(config.api.urls.internal + path, request);
};
+2 -2
utils/config.json
···
"version": "0.0.1",
"devBuild": true,
"api": {
+
"enabled": true,
"urls": {
"public": "https://api.polytoria.com/v1/",
"internal": "https://polytoria.com/api/"
-
},
-
"fallback": false
+
}
}
}
+11 -5
utils/utilities.ts
···
console.info('[Poly+] "' + key + '" cache is stale replenishing...', timeAgo(overlap));
const replenishedCache = await replenish();
-
cacheStorage[key] = replenishedCache;
-
metadata[key] = Date.now();
-
cache.setValue(cacheStorage);
-
cache.setMeta(metadata);
-
}
+
// Don't cache the response when the config file has APIs disabled
+
if (replenishedCache != "disabled") {
+
cacheStorage[key] = replenishedCache;
+
metadata[key] = Date.now();
+
+
cache.setValue(cacheStorage);
+
cache.setMeta(metadata);
+
} else {
+
return "disabled";
+
};
+
};
return cacheStorage[key];
};
+14 -2
wxt.config.ts
···
manifest: {
permissions: [
"https://*.polytoria.com/*",
-
"storage"
+
"storage",
+
"activeTab"
],
browser_specific_settings: {
gecko: {
id: "index.business.purposes@gmail.com"
}
-
}
+
},
+
web_accessible_resources: [
+
{
+
"resources": [
+
"css/*",
+
"icon/*",
+
"images/*",
+
"svgs/*"
+
],
+
"matches": ["https://*.polytoria.com/*"]
+
}
+
]
},
runner: {
startUrls: ["https://polytoria.com/home"],