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: Accept/Decline all friend requests feature

Index ef21f3e7 b80e7949

Changed files
+128 -9
entrypoints
utils
+73
entrypoints/account.content/friends.ts
···
+
import * as api from "@/utils/api";
+
+
export function actions() {
+
const container = document.getElementById('friends-container')!;
+
+
const actionBtns = document.createElement('div');
+
actionBtns.classList.add('row', 'mb-3');
+
actionBtns.innerHTML = `
+
<div class="col">
+
<button class="btn btn-success w-100">
+
Accept All
+
</button>
+
</div>
+
<div class="col">
+
<button class="btn btn-danger w-100">
+
Decline All
+
</button>
+
</div>
+
`;
+
+
const acceptAll: HTMLButtonElement = actionBtns.querySelector('.btn-success')!;
+
const declineAll: HTMLButtonElement = actionBtns.querySelector('.btn-danger')!;
+
+
const firstPage = Array.from(container.getElementsByTagName('a'))
+
.map((link) => link.getAttribute('href')?.split('/')[2]);
+
+
//api.iterate('internal', '/friends?page=', 1).then(data => console.log(data))
+
+
const setDisabled = function(value: boolean) {
+
acceptAll.disabled = value;
+
declineAll.disabled = value;
+
};
+
+
if (firstPage.length == 0) {
+
setDisabled(true);
+
} else {
+
acceptAll.addEventListener('click', async () => {
+
setDisabled(true);
+
+
const ids = await api.iterate('internal', '/friends/requests?page=', 1);
+
const payloads = ids.map((request: any) => ({
+
method: 'POST',
+
headers: {
+
'Content-Type': 'application/json'
+
},
+
body: JSON.stringify({
+
userID: request.senderID
+
})
+
}));
+
api.batchAction('/friends/send', payloads);
+
});
+
+
declineAll.addEventListener('click', async () => {
+
setDisabled(true);
+
+
const ids = await api.iterate('internal', '/friends/requests?page=', 1);
+
const payloads = ids.map((request: any) => ({
+
method: 'POST',
+
headers: {
+
'Content-Type': 'application/json'
+
},
+
body: JSON.stringify({
+
userID: request.senderID
+
})
+
}));
+
api.batchAction('/friends/remove', payloads);
+
});
+
};
+
+
container.parentElement!.insertBefore(actionBtns, container);
+
};
+
+
export function checkboxes() {};
+15
entrypoints/account.content/index.ts
···
+
import { preferences } from "@/utils/storage";
+
import * as friends from "./friends";
+
+
export default defineContentScript({
+
matches: ['*://polytoria.com/my/*'],
+
main() {
+
preferences.getPreferences()
+
.then((values) => {
+
if (window.location.pathname.includes('friends')) {
+
// View
+
if (values.improvedFriendLists.enabled) friends.actions();
+
};
+
});
+
}
+
});
+2 -2
entrypoints/home.content.ts
···
const placeData: Array<placeApiSchema> = await pullCache(
'favoritedPlaces',
-
async () => await api.batch('/places/', places),
+
async () => await api.batch('public', '/places/', places),
300000,
false
);
···
.then(async (friends) => {
const userData = await pullCache(
'bestFriends',
-
async () => await api.batch('/users/', friends),
+
async () => await api.batch('internal', '/users/', friends),
300000,
false
);
+34 -6
utils/api.ts
···
import config from "./config.json";
-
import { userApiSchema, placeApiSchema } from "./types";
-
export async function batch(path: string, ids: string[]): Promise<any> {
-
const res: Record<string, userApiSchema> = {};
-
for (let id of ids) {
-
const info = await (await fetch(config.api.url + path + id)).json();
+
export async function batch(
+
type: "public" | "internal",
+
path: string,
+
ids: string[],
+
headers?: Record<string, any>
+
): Promise<any> {
+
if (!headers) headers = {};
+
const res: Record<string, any> = {};
+
+
for (const id of ids) {
+
const info = await (await fetch(config.api.urls[type] + path + id, headers)).json();
res[id] = info;
-
}
+
};
return res;
+
};
+
+
export async function iterate(type: "public" | "internal", path: string, startPage: number, endingPage?: number): Promise<any> {
+
let res: Array<any> = [];
+
const firstPage: {
+
meta: Record<string, any>,
+
data: Array<any>
+
} = await (await fetch(config.api.urls[type] + path + 1)).json();
+
res.push(...firstPage.data);
+
+
if (!endingPage) endingPage = firstPage.meta.lastPage;
+
for (let index = startPage + 1; index < endingPage!; index++) {
+
const page = await (await fetch(config.api.urls[type] + path + index)).json();
+
res.push(...page.data);
+
};
+
return res;
+
};
+
+
export async function batchAction(path: string, headers: Array<Record<string, any>>) {
+
for (const request of headers) {
+
fetch(config.api.urls.internal + path, request);
+
};
};
+4 -1
utils/config.json
···
"version": "0.0.1",
"devBuild": true,
"api": {
-
"url": "https://api.polytoria.com/v1/",
+
"urls": {
+
"public": "https://api.polytoria.com/v1/",
+
"internal": "https://polytoria.com/api/"
+
},
"fallback": false
}
}