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: Download .poly File feature

Index be4a6e3e 761fcac3

Changed files
+102 -6
entrypoints
places.content
utils
+16 -2
entrypoints/places.content/index.ts
···
import { preferences } from "@/utils/storage";
+
import config from "@/utils/config.json";
import * as view from "./view";
+
import * as manage from "./manage";
export default defineContentScript({
-
matches: ['*://polytoria.com/places/*'],
+
matches: [
+
'*://polytoria.com/places/*',
+
'*://polytoria.com/create/place/*'
+
],
main() {
preferences.getPreferences()
.then((values) => {
-
if (window.location.pathname.split('/')[2]) {
+
const [_, first, second] = window.location.pathname.split('/');
+
+
if (!isNaN(Number(second))) {
// View
+
if (config.devBuild) console.log('[Poly+] Running view page functions: ', view);
+
if (values.favoritedPlaces.enabled) view.favoritedPlaces();
if (values.placeRevenue.enabled) view.approxPlaceRevenue();
+
} else if (first === "create" && values.placeManagement.enabled) {
+
// Manage
+
if (config.devBuild) console.log('[Poly+] Running manage page functions: ', manage);
+
+
if (values.placeManagement.download) manage.placeFileExport();
};
});
}
+69
entrypoints/places.content/manage.ts
···
+
import config from "@/utils/config.json";
+
import { userDetails } from "@/utils/types";
+
import * as apiTypes from "@/utils/api/types";
+
const placeID = window.location.pathname.split('/')[3];
+
+
/**
+
* Adds a button to the manage page of places allowing users to quickly download their place files from the website.
+
*/
+
export function placeFileExport() {
+
if (!config.api.enabled) {
+
throw new Error("[Poly+] API is disabled, cancelling place file export loading..");
+
};
+
+
const retrievePlaceFile = async function() {
+
const editReq: apiTypes.editApiSchema = (await (await fetch(config.api.urls.internal + 'places/edit/', {
+
method: 'POST',
+
body: JSON.stringify({
+
placeID: placeID
+
})
+
})).json());
+
+
if (!editReq.success) {
+
throw new Error("[Poly+] There was an error while retrieving the authenticated user's creator authorization token.");
+
};
+
+
const placeContents = (await (await fetch(`${config.api.urls.public}places/get-place?id=${placeID}&tokenType=creator`, {
+
headers: {
+
Authorization: editReq.token
+
}
+
})).blob());
+
+
return placeContents;
+
};
+
+
const container = document.createElement('div');
+
container.classList.add('form-group', 'mt-4');
+
container.innerHTML = `
+
<label class="mb-2">
+
<h5 class="mb-0">Download <code style="color: orange;">.poly</code> File</h5>
+
<small class="text-muted">Quickly download your place from the site!</small>
+
</label>
+
<br>
+
<button type="button" class="btn btn-primary">Download</button>
+
`;
+
+
const form = document.querySelector('form[action="/create/place/update"]')!;
+
const button = container.getElementsByTagName('button')[0]!;
+
+
form.insertBefore(container, form.children[form.children.length - 1]);
+
+
button.addEventListener('click', async () => {
+
button.innerHTML = `
+
<span class="spinner-grow spinner-grow-sm" aria-hidden="true"></span>
+
<span class="visually-hidden" role="status">Loading...</span>
+
`;
+
+
const placeContents = await retrievePlaceFile();
+
const blob = URL.createObjectURL(placeContents as any);
+
const link = document.createElement('a');
+
+
link.href = blob;
+
link.download = placeID + '.poly';
+
document.body.appendChild(link);
+
link.click();
+
link.remove();
+
+
button.textContent = 'Download';
+
});
+
};
+5
utils/api/types.ts
···
}>,
pages: number,
total: number
+
};
+
+
export type editApiSchema = {
+
success: boolean,
+
token: string
};
+2 -1
utils/config.json
···
"urls": {
"public": "https://api.polytoria.com/v1/",
"internal": "https://polytoria.com/api/",
-
"itemview": "https://polytoria.com/ptstatic/itemview/#"
+
"itemview": "https://polytoria.com/ptstatic/itemview/#",
+
"extension": "http://localhost:3000/v1/"
}
},
"limits": {
+8 -1
utils/storage.ts
···
tryItems: { enabled: true },
outfitCost: { enabled: true },
placeRevenue: { enabled: true },
-
accurateOwners: { enabled: true }
+
accurateOwners: { enabled: true },
+
placeManagement: {
+
enabled: true,
+
activityToggle: true,
+
download: true,
+
multipleWhitelist: true,
+
clearWhitelist: true
+
}
}
export type preferencesSchema = typeof defaultPreferences & {
+2 -2
utils/utilities.ts
···
return avatar as avatarApiSchema;
} else {
return "disabled";
-
}
-
},
+
};
+
}
};
}