lmlfc-bttv/src/main.ts

110 lines
2.9 KiB
TypeScript
Raw Normal View History

2023-12-28 21:40:08 +00:00
const emote_regex = /bttv:([^\s]+)/gi;
2023-12-28 13:55:42 +00:00
2023-12-28 15:37:38 +00:00
type Emote = {
code: string;
2023-12-28 16:16:15 +00:00
url?: string;
};
type BTTV_Emote = {
id: string;
code: string;
imageType: string;
animated: boolean;
user: any;
2023-12-28 15:37:38 +00:00
};
async function bttv_get_url(code: string): Promise<Emote> {
2023-12-28 16:16:15 +00:00
const res = await fetch(
`https://api.betterttv.net/3/emotes/shared/search?query=${code}&offset=0&limit=50`,
);
const content = await res.json();
if (!Array.isArray(content)) return { code: code };
const matches = (content as BTTV_Emote[]).filter(
(be) => be.code.toLowerCase() == code.toLowerCase(),
);
if (matches.length <= 0) return { code: code };
2023-12-28 15:37:38 +00:00
return {
code: code,
2023-12-28 21:11:47 +00:00
url: `//cdn.betterttv.net/emote/${matches[0].id}/1x.${matches[0].imageType}`,
2023-12-28 15:37:38 +00:00
};
}
type EmoteMap = { [code: string]: string };
async function get_emotes(codes: Iterable<string>): Promise<EmoteMap> {
const codes_set = new Set(codes);
// queue emote jobs
const queue = [...codes_set].map((code) => bttv_get_url(code));
2023-12-28 21:11:47 +00:00
console.log("[lmlfc-bttv] queued", queue.length, "jobs");
2023-12-28 15:37:38 +00:00
// run
const result: EmoteMap = {};
for (const job of await Promise.all(queue)) {
2023-12-28 16:16:15 +00:00
if (job.url) result[job.code] = job.url;
2023-12-28 15:37:38 +00:00
}
return result;
2023-12-28 13:55:42 +00:00
}
async function process_text(text: string): Promise<string> {
2023-12-28 15:37:38 +00:00
const matches = [...text.matchAll(emote_regex)];
2023-12-28 21:11:47 +00:00
const emotes = await get_emotes(matches.map(([_, code]) => code));
2023-12-28 15:37:38 +00:00
for (const emote of matches.reverse()) {
const [match, code] = emote;
const index = emote.index ?? 0;
2023-12-28 16:31:04 +00:00
if (!(code in emotes)) continue;
2023-12-28 13:55:42 +00:00
2023-12-28 15:37:38 +00:00
text =
text.substring(0, index) +
2023-12-28 16:16:15 +00:00
`[not]${emotes[code]}[/not]` +
2023-12-28 15:37:38 +00:00
text.substring(index + match.length);
}
2023-12-28 16:16:15 +00:00
text = text.replace(/\[\/not\]\s+\[not\]/g, "[/not][not]");
2023-12-28 13:55:42 +00:00
return text;
}
(() => {
const cb_form = document.querySelector("#mgc_cb_evo_form");
if (!(cb_form instanceof HTMLFormElement)) return;
2023-12-28 21:40:08 +00:00
const cb_send = document.querySelector(
"#mgc_cb_evo_form > input[type=image]:nth-child(2)",
);
if (!(cb_send instanceof HTMLInputElement)) return;
2023-12-28 13:55:42 +00:00
const bttv_btn = (() => {
const btn = document.createElement("a");
btn.style.setProperty("cursor", "pointer");
btn.style.setProperty("margin-right", "4px");
const img = document.createElement("img");
2023-12-28 21:28:02 +00:00
img.setAttribute("src", chrome.runtime.getURL("img/sb_button.png"));
2023-12-28 21:40:08 +00:00
img.setAttribute("alt", "bttv emotes ersetzen und absenden");
img.setAttribute("title", "bttv:* emotes ersetzen und absenden");
2023-12-28 13:55:42 +00:00
img.style.setProperty("vertical-align", "middle");
2023-12-28 21:40:08 +00:00
btn.addEventListener("click", async () => {
2023-12-28 13:55:42 +00:00
const cb_input = document.querySelector("#mgc_cb_evo_input");
if (!(cb_input instanceof HTMLInputElement)) return;
2023-12-28 16:16:15 +00:00
cb_input.value = await process_text(cb_input.value);
cb_input.focus();
2023-12-28 21:40:08 +00:00
cb_send.click();
2023-12-28 13:55:42 +00:00
});
btn.appendChild(img);
return btn;
})();
2023-12-28 21:40:08 +00:00
cb_form.insertBefore(bttv_btn, cb_send);
2023-12-28 13:55:42 +00:00
console.log("done.");
})();