mirror of
https://github.com/ItsVipra/ProToots
synced 2024-11-25 13:00:18 +00:00
parent
f032dcca3f
commit
bee683036d
4 changed files with 78 additions and 9 deletions
|
@ -60,7 +60,7 @@ export async function fetchPronouns(dataID, accountName, type) {
|
|||
status = await fetchStatus(dataID);
|
||||
}
|
||||
|
||||
let pronouns = extractFromStatus(status);
|
||||
let pronouns = await extractFromStatus(status);
|
||||
if (!pronouns) {
|
||||
pronouns = "null";
|
||||
//TODO: if no field check bio
|
||||
|
|
|
@ -2,7 +2,7 @@ import sanitizeHtml from "sanitize-html";
|
|||
|
||||
const fieldMatchers = [/pro.*nouns?/i, "pronomen"];
|
||||
const knownPronounUrls = [
|
||||
/pronouns\.page\/([\w/]+)/,
|
||||
/pronouns\.page\/:?([\w/@]+)/,
|
||||
/pronouns\.within\.lgbt\/([\w/]+)/,
|
||||
/pronouns\.cc\/pronouns\/([\w/]+)/,
|
||||
];
|
||||
|
@ -14,9 +14,9 @@ const knownPronounUrls = [
|
|||
* If found, it sanitizes and returns the value of said field.
|
||||
*
|
||||
* @param {any} status
|
||||
* @returns {string|null} Author pronouns if found. Otherwise returns null.
|
||||
* @returns {Promise<string|null>} Author pronouns if found. Otherwise returns null.
|
||||
*/
|
||||
export function extractFromStatus(status) {
|
||||
export async function extractFromStatus(status) {
|
||||
// get account from status and pull out fields
|
||||
const account = status.account;
|
||||
const fields = account.fields;
|
||||
|
@ -42,6 +42,62 @@ export function extractFromStatus(status) {
|
|||
text = pronounsRaw.match(knownUrlRe)[1];
|
||||
}
|
||||
|
||||
// Right now, only the pronoun.page regex matches the @usernames.
|
||||
if (text.charAt(0) === "@") {
|
||||
text = await queryPronounsFromPronounsPage(text.substring(1));
|
||||
}
|
||||
|
||||
if (!text) return null;
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the pronouns from the pronouns.page API.
|
||||
* @param {string} username The username of the person.
|
||||
* @returns {Promise<string|null>} The pronouns that have set the "yes" opinion.
|
||||
*/
|
||||
async function queryPronounsFromPronounsPage(username) {
|
||||
// Example page: https://en.pronouns.page/api/profile/get/andrea?version=2
|
||||
const resp = await fetch(`https://en.pronouns.page/api/profile/get/${username}?version=2`);
|
||||
if (resp.status >= 400) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { profiles } = await resp.json();
|
||||
if (!profiles) return null;
|
||||
|
||||
// Unfortunately, pronouns.page does not return a 404 if a profile does not exist, but an empty profiles object. :clown_face:
|
||||
if (!Object.keys(profiles).length) return null;
|
||||
|
||||
let pronouns;
|
||||
// Query the pronouns in the following language order:
|
||||
// 1. The mastodon interface language
|
||||
// 2. The spoken languages according to the user
|
||||
// 3. The english language.
|
||||
const languages = [document.documentElement.lang, ...window.navigator.languages, "en"];
|
||||
for (const lang of languages) {
|
||||
if (lang in profiles) {
|
||||
pronouns = profiles[lang].pronouns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have a value yet, just take the first profile.
|
||||
if (!pronouns) pronouns = profiles[0].pronouns;
|
||||
|
||||
let val = pronouns.find((x) => x.opinion === "yes").value;
|
||||
val = sanitizePronounPageValue(val);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} val
|
||||
*/
|
||||
function sanitizePronounPageValue(val) {
|
||||
if (!val.startsWith("https://")) return val;
|
||||
|
||||
val = val.replace(/https?:\/\/.+\.pronouns\.page\/:?/, "");
|
||||
|
||||
if (val === "no-pronouns") val = "no pronouns";
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
"description": "puts pronouns next to usernames on mastodon",
|
||||
"homepage_url": "https://github.com/ItsVipra/ProToots",
|
||||
"permissions": ["storage"],
|
||||
"permissions": ["storage", "https://en.pronouns.page/api/profile/get/*"],
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": "icons/icon small_size/icon small_size.png",
|
||||
|
|
|
@ -13,8 +13,8 @@ const validFields = [
|
|||
];
|
||||
|
||||
for (const field of validFields) {
|
||||
extract(`${field} is extracted`, () => {
|
||||
const result = pronouns.extractFromStatus({
|
||||
extract(`${field} is extracted`, async () => {
|
||||
const result = await pronouns.extractFromStatus({
|
||||
account: {
|
||||
fields: [{ name: field, value: "pro/nouns" }],
|
||||
},
|
||||
|
@ -30,12 +30,19 @@ valueExtractionSuite.before(() => {
|
|||
global.window = {
|
||||
// @ts-ignore
|
||||
navigator: {
|
||||
language: "en",
|
||||
languages: ["en"],
|
||||
},
|
||||
};
|
||||
global.document = {
|
||||
// @ts-ignore
|
||||
documentElement: {
|
||||
lang: "de",
|
||||
},
|
||||
};
|
||||
});
|
||||
valueExtractionSuite.after(() => {
|
||||
global.window = undefined;
|
||||
global.document = undefined;
|
||||
});
|
||||
const valueExtractionTests = [
|
||||
["she/her", "she/her"], // exact match
|
||||
|
@ -44,7 +51,13 @@ const valueExtractionTests = [
|
|||
["https://en.pronouns.page/they/them", "they/them"], // plain-text "URLs"
|
||||
["pronouns.page/they/them", "they/them"], // plain-text "URLs" without scheme
|
||||
[`<a href="https://en.pronouns.page/they/them"></a>`, "they/them"], // HTML-formatted URLs
|
||||
[`<a href="https://en.pronouns.page/@Vipra"></a>`, null], // pronoun pages with usernames
|
||||
[`<a href="https://en.pronouns.page/@Vipra"></a>`, "she/her"], // pronoun pages with usernames
|
||||
[
|
||||
`<a href="https://en.pronouns.page/@definitely_not_existing_username_on_pronouns_page"></a>`,
|
||||
null,
|
||||
], // 404 errors
|
||||
[`<a href="https://de.pronouns.page/:Katze"></a>`, "Katze"], // custom pronouns
|
||||
[`<a href="https://de.pronouns.page/@benaryorg"></a>`, "Katze"], // custom pronouns in profile
|
||||
];
|
||||
for (const [input, expects] of valueExtractionTests) {
|
||||
valueExtractionSuite(input, async () => {
|
||||
|
|
Loading…
Reference in a new issue