mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 11:49:25 +00:00
Add 7TV emote support
This commit is contained in:
@@ -9,6 +9,7 @@ setUpElectronWindowFrame();
|
||||
const renderer = new BroadcastRenderer({ canvas, scriptLayer, broadcaster, showToast });
|
||||
const defaultScriptSettings = {
|
||||
allowChannelEmotesForAssets: true,
|
||||
allowSevenTvEmotesForAssets: true,
|
||||
allowScriptChatAccess: true,
|
||||
};
|
||||
let currentScriptSettings = { ...defaultScriptSettings };
|
||||
@@ -29,15 +30,33 @@ const settingsPromise = fetch(`/api/channels/${encodeURIComponent(broadcaster)}/
|
||||
renderer.setScriptSettings(defaultScriptSettings);
|
||||
});
|
||||
|
||||
fetch(`/api/twitch/emotes?channel=${encodeURIComponent(broadcaster)}`)
|
||||
const emoteCatalog = { global: [], channel: [], sevenTv: [] };
|
||||
const twitchEmotePromise = fetch(`/api/twitch/emotes?channel=${encodeURIComponent(broadcaster)}`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load Twitch emotes");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((catalog) => renderer.setEmoteCatalog(catalog))
|
||||
.then((catalog) => {
|
||||
emoteCatalog.global = Array.isArray(catalog?.global) ? catalog.global : [];
|
||||
emoteCatalog.channel = Array.isArray(catalog?.channel) ? catalog.channel : [];
|
||||
})
|
||||
.catch((error) => console.warn("Unable to load Twitch emotes", error));
|
||||
|
||||
const sevenTvEmotePromise = fetch(`/api/7tv/emotes?channel=${encodeURIComponent(broadcaster)}`)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to load 7TV emotes");
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((catalog) => {
|
||||
emoteCatalog.sevenTv = Array.isArray(catalog?.channel) ? catalog.channel : [];
|
||||
})
|
||||
.catch((error) => console.warn("Unable to load 7TV emotes", error));
|
||||
|
||||
Promise.allSettled([twitchEmotePromise, sevenTvEmotePromise]).then(() => renderer.setEmoteCatalog(emoteCatalog));
|
||||
let disconnectChat = () => {};
|
||||
settingsPromise.finally(() => {
|
||||
if (!currentScriptSettings.allowScriptChatAccess) {
|
||||
|
||||
@@ -30,8 +30,11 @@ export class BroadcastRenderer {
|
||||
this.emoteCatalogById = new Map();
|
||||
this.globalEmotes = [];
|
||||
this.channelEmotes = [];
|
||||
this.sevenTvEmotes = [];
|
||||
this.sevenTvEmotesByName = new Map();
|
||||
this.lastChatPruneAt = 0;
|
||||
this.allowChannelEmotesForAssets = true;
|
||||
this.allowSevenTvEmotesForAssets = true;
|
||||
this.allowScriptChatAccess = true;
|
||||
|
||||
this.obsBrowser = !!globalThis.obsstudio;
|
||||
@@ -429,6 +432,7 @@ export class BroadcastRenderer {
|
||||
|
||||
setScriptSettings(settings) {
|
||||
this.allowChannelEmotesForAssets = settings?.allowChannelEmotesForAssets !== false;
|
||||
this.allowSevenTvEmotesForAssets = settings?.allowSevenTvEmotesForAssets !== false;
|
||||
this.allowScriptChatAccess = settings?.allowScriptChatAccess !== false;
|
||||
if (!this.allowScriptChatAccess) {
|
||||
this.chatMessages = [];
|
||||
@@ -478,15 +482,22 @@ export class BroadcastRenderer {
|
||||
setEmoteCatalog(catalog) {
|
||||
this.globalEmotes = Array.isArray(catalog?.global) ? catalog.global : [];
|
||||
this.channelEmotes = Array.isArray(catalog?.channel) ? catalog.channel : [];
|
||||
this.sevenTvEmotes = Array.isArray(catalog?.sevenTv) ? catalog.sevenTv : [];
|
||||
this.refreshEmoteCatalog();
|
||||
}
|
||||
|
||||
refreshEmoteCatalog() {
|
||||
const allowedChannelEmotes = this.allowChannelEmotesForAssets ? this.channelEmotes : [];
|
||||
this.emoteCatalog = [...this.globalEmotes, ...allowedChannelEmotes];
|
||||
const allowedSevenTvEmotes = this.allowSevenTvEmotesForAssets ? this.sevenTvEmotes : [];
|
||||
this.emoteCatalog = [...this.globalEmotes, ...allowedChannelEmotes, ...allowedSevenTvEmotes];
|
||||
this.emoteCatalogById = new Map(
|
||||
this.emoteCatalog.map((entry) => [String(entry?.id || ""), entry]).filter(([key]) => key),
|
||||
);
|
||||
this.sevenTvEmotesByName = new Map(
|
||||
allowedSevenTvEmotes
|
||||
.map((entry) => [String(entry?.name || ""), entry])
|
||||
.filter(([key]) => key),
|
||||
);
|
||||
if (this.chatMessages.length) {
|
||||
this.chatMessages = this.chatMessages.map((message) => {
|
||||
const fragments = this.buildMessageFragments(message.message || "", message.tags);
|
||||
@@ -534,7 +545,7 @@ export class BroadcastRenderer {
|
||||
}
|
||||
const emotes = this.parseEmoteOffsets(tags?.emotes);
|
||||
if (!emotes.length) {
|
||||
return [{ type: "text", text: message }];
|
||||
return this.applySevenTvEmotes([{ type: "text", text: message }]);
|
||||
}
|
||||
const sorted = emotes.sort((a, b) => a.start - b.start);
|
||||
const fragments = [];
|
||||
@@ -561,7 +572,43 @@ export class BroadcastRenderer {
|
||||
if (cursor < message.length) {
|
||||
fragments.push({ type: "text", text: message.slice(cursor) });
|
||||
}
|
||||
return fragments;
|
||||
return this.applySevenTvEmotes(fragments);
|
||||
}
|
||||
|
||||
applySevenTvEmotes(fragments) {
|
||||
if (!this.sevenTvEmotesByName.size) {
|
||||
return fragments;
|
||||
}
|
||||
const enhanced = [];
|
||||
fragments.forEach((fragment) => {
|
||||
if (fragment?.type !== "text" || !fragment.text) {
|
||||
enhanced.push(fragment);
|
||||
return;
|
||||
}
|
||||
const parts = fragment.text.split(/(\\s+)/);
|
||||
parts.forEach((part) => {
|
||||
if (!part) {
|
||||
return;
|
||||
}
|
||||
if (/^\\s+$/.test(part)) {
|
||||
enhanced.push({ type: "text", text: part });
|
||||
return;
|
||||
}
|
||||
const emote = this.sevenTvEmotesByName.get(part);
|
||||
if (emote) {
|
||||
enhanced.push({
|
||||
type: "emote",
|
||||
id: emote.id,
|
||||
text: part,
|
||||
name: emote.name || part,
|
||||
url: emote.url || null,
|
||||
});
|
||||
} else {
|
||||
enhanced.push({ type: "text", text: part });
|
||||
}
|
||||
});
|
||||
});
|
||||
return enhanced;
|
||||
}
|
||||
|
||||
receiveChatMessage(message) {
|
||||
|
||||
@@ -8,6 +8,7 @@ const elements = {
|
||||
canvasStatus: document.getElementById("canvas-status"),
|
||||
canvasSaveButton: document.getElementById("save-canvas-btn"),
|
||||
allowChannelEmotes: document.getElementById("allow-channel-emotes"),
|
||||
allowSevenTvEmotes: document.getElementById("allow-7tv-emotes"),
|
||||
allowScriptChat: document.getElementById("allow-script-chat"),
|
||||
scriptSettingsStatus: document.getElementById("script-settings-status"),
|
||||
scriptSettingsSaveButton: document.getElementById("save-script-settings-btn"),
|
||||
@@ -250,6 +251,9 @@ function renderScriptSettings(settings) {
|
||||
if (elements.allowChannelEmotes) {
|
||||
elements.allowChannelEmotes.checked = settings.allowChannelEmotesForAssets !== false;
|
||||
}
|
||||
if (elements.allowSevenTvEmotes) {
|
||||
elements.allowSevenTvEmotes.checked = settings.allowSevenTvEmotesForAssets !== false;
|
||||
}
|
||||
if (elements.allowScriptChat) {
|
||||
elements.allowScriptChat.checked = settings.allowScriptChatAccess !== false;
|
||||
}
|
||||
@@ -260,13 +264,18 @@ async function fetchScriptSettings() {
|
||||
const data = await fetchJson("/settings", {}, "Failed to load script settings");
|
||||
renderScriptSettings(data);
|
||||
} catch (error) {
|
||||
renderScriptSettings({ allowChannelEmotesForAssets: true, allowScriptChatAccess: true });
|
||||
renderScriptSettings({
|
||||
allowChannelEmotesForAssets: true,
|
||||
allowSevenTvEmotesForAssets: true,
|
||||
allowScriptChatAccess: true,
|
||||
});
|
||||
showToast("Using default script settings. Unable to load saved preferences.", "warning");
|
||||
}
|
||||
}
|
||||
|
||||
async function saveScriptSettings() {
|
||||
const allowChannelEmotesForAssets = elements.allowChannelEmotes?.checked ?? true;
|
||||
const allowSevenTvEmotesForAssets = elements.allowSevenTvEmotes?.checked ?? true;
|
||||
const allowScriptChatAccess = elements.allowScriptChat?.checked ?? true;
|
||||
if (elements.scriptSettingsStatus) elements.scriptSettingsStatus.textContent = "Saving...";
|
||||
setButtonBusy(elements.scriptSettingsSaveButton, true, "Saving...");
|
||||
@@ -276,7 +285,11 @@ async function saveScriptSettings() {
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ allowChannelEmotesForAssets, allowScriptChatAccess }),
|
||||
body: JSON.stringify({
|
||||
allowChannelEmotesForAssets,
|
||||
allowSevenTvEmotesForAssets,
|
||||
allowScriptChatAccess,
|
||||
}),
|
||||
},
|
||||
"Failed to save script settings",
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user