From c57bfd75fbd6b8cd4272ca6b494b89fb7c9b414d Mon Sep 17 00:00:00 2001 From: liyunze <50455574+liyunze-coding@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:27:37 +1000 Subject: [PATCH] fixed sync issues --- Code.cs | 37 +- widgets/horizontal/README.md | 2 +- widgets/horizontal/index.html | 8 +- widgets/horizontal/scripts/emotes.js | 273 -------- widgets/horizontal/scripts/streamerbot.js | 200 ------ widgets/horizontal/scripts/tasklist-view.js | 591 ------------------ .../images/websocket.png | Bin .../lib/streamerbot-client.js | 0 .../{vertical => shared}/scripts/emotes.js | 0 .../scripts/streamerbot.js | 118 ++-- .../scripts/tasklist-view.js | 0 widgets/streamer-only/README.md | 2 +- widgets/streamer-only/images/websocket.png | Bin 82494 -> 0 bytes widgets/streamer-only/index.html | 6 +- .../streamer-only/lib/streamerbot-client.js | 1 - widgets/streamer-only/scripts/emotes.js | 273 -------- widgets/streamer-only/scripts/streamerbot.js | 201 ------ widgets/vertical/README.md | 2 +- widgets/vertical/images/websocket.png | Bin 82494 -> 0 bytes widgets/vertical/index.html | 8 +- widgets/vertical/lib/streamerbot-client.js | 1 - 21 files changed, 101 insertions(+), 1622 deletions(-) delete mode 100644 widgets/horizontal/scripts/emotes.js delete mode 100644 widgets/horizontal/scripts/streamerbot.js delete mode 100644 widgets/horizontal/scripts/tasklist-view.js rename widgets/{horizontal => shared}/images/websocket.png (100%) rename widgets/{horizontal => shared}/lib/streamerbot-client.js (100%) rename widgets/{vertical => shared}/scripts/emotes.js (100%) rename widgets/{vertical => shared}/scripts/streamerbot.js (67%) rename widgets/{vertical => shared}/scripts/tasklist-view.js (100%) delete mode 100644 widgets/streamer-only/images/websocket.png delete mode 100644 widgets/streamer-only/lib/streamerbot-client.js delete mode 100644 widgets/streamer-only/scripts/emotes.js delete mode 100644 widgets/streamer-only/scripts/streamerbot.js delete mode 100644 widgets/vertical/images/websocket.png delete mode 100644 widgets/vertical/lib/streamerbot-client.js diff --git a/Code.cs b/Code.cs index ef9bbd2..c6a2d66 100644 --- a/Code.cs +++ b/Code.cs @@ -464,7 +464,7 @@ public class TaskOperations } int newIndex = taskData[key].Tasks.Count - 1; - broadcast(new { mode = "refresh", task = taskName, completed = completed, focused = focused }, null); + broadcast(new { mode = "add", task = taskName, completed = completed, focused = focused }, null); return new Response<(int, string)>(true, (newIndex, taskName), null); } @@ -481,7 +481,7 @@ public class TaskOperations string oldName = userTasks[index].Name; userTasks[index].Name = newTask; SaveIntoTasks(userTasks); - broadcast(new { mode = "refresh", index = index, task = newTask }, null); + broadcast(new { mode = "edit", index = index, task = newTask }, null); return new Response<(string, string)>(true, (oldName, newTask), null); } @@ -502,7 +502,7 @@ public class TaskOperations UnfocusAll(tasks); tasks[n].Focused = true; SaveIntoTasks(tasks); - broadcast(new { mode = "refresh", index = n }, null); + broadcast(new { mode = "focus", index = n }, null); return new Response<(int, string)>(true, (n, tasks[n].Name), null); } else if (indexByName > -1) @@ -513,7 +513,7 @@ public class TaskOperations UnfocusAll(tasks); tasks[n].Focused = true; SaveIntoTasks(tasks); - broadcast(new { mode = "refresh", index = n }, null); + broadcast(new { mode = "focus", index = n }, null); return new Response<(int, string)>(true, (n, tasks[n].Name), null); } else @@ -521,7 +521,7 @@ public class TaskOperations var response = AddTask(rawInput, false, true); if (response.Success) { - broadcast(new { mode = "refresh", index = response.Data.Item1 }, null); + broadcast(new { mode = "focus", index = response.Data.Item1 }, null); return new Response<(int, string)>(true, response.Data, null); } @@ -846,9 +846,9 @@ public class CPHInline string completedTaskName = userTasks[focusedTaskIndex].Name; userTasks[focusedTaskIndex].Completed = true; userTasks[focusedTaskIndex].Focused = false; - Broadcast(new { mode = "refresh", index = focusedTaskIndex }, null); operations.SaveIntoTasks(userTasks); SaveTasks(); + Broadcast(new { mode = "done", index = focusedTaskIndex }, null); Respond(BotResponses.NextSuccess(completedTaskName, focusResponse.Data.Item1 + 1, focusResponse.Data.Item2)); return true; } @@ -997,12 +997,15 @@ public class CPHInline foreach (int i in taskIndices.OrderByDescending(n => n)) { userTasks.RemoveAt(i); - Broadcast(new { mode = "refresh", index = i }, null); } operations.SaveIntoTasks(userTasks); operations.Cleanup(true); SaveTasks(); + foreach (int i in taskIndices.OrderByDescending(n => n)) + { + Broadcast(new { mode = "remove", index = i }, null); + } Respond(MessageBuilder.BuildRemoveMessage(tasksRemoved, tasksFailedToRemove, allTasks)); return true; } @@ -1024,7 +1027,7 @@ public class CPHInline operations.RemoveUser(key); SaveTasks(); Respond(BotResponses.AdminDeleteSuccess); - Broadcast(new { mode = "refresh", id = key }, null); + Broadcast(new { mode = "admindelete", id = key }, null); return true; } @@ -1081,12 +1084,15 @@ public class CPHInline { userTasks[i].Completed = true; userTasks[i].Focused = false; - Broadcast(new { mode = "refresh", index = i }, null); } IncrementDoneCount(taskIndices.Count); operations.SaveIntoTasks(userTasks); SaveTasks(); + foreach (int i in taskIndices) + { + Broadcast(new { mode = "done", index = i }, null); + } Respond(MessageBuilder.BuildCompletedMessage(tasksCompleted, tasksFailedToComplete, allTasks)); return true; } @@ -1096,7 +1102,7 @@ public class CPHInline operations.Unfocus(); SaveTasks(); Respond(BotResponses.Unfocused); - Broadcast(new { mode = "refresh" }, null); + Broadcast(new { mode = "unfocus" }, null); return true; } @@ -1144,11 +1150,14 @@ public class CPHInline { userTasks[i].Completed = false; userTasks[i].Focused = false; - Broadcast(new { mode = "refresh", index = i }, null); } operations.SaveIntoTasks(userTasks); SaveTasks(); + foreach (int i in taskIndices) + { + Broadcast(new { mode = "undone", index = i }, null); + } Respond(MessageBuilder.BuildUndoneMessage(tasksCompleted, tasksFailedToComplete)); return true; } @@ -1169,7 +1178,7 @@ public class CPHInline operations.ClearUserCompletedTasks(key); operations.Cleanup(false); SaveTasks(); - Broadcast(new { mode = "refresh" }, null); + Broadcast(new { mode = "clearmydone" }, null); Respond(BotResponses.ClearMyDone); return true; } @@ -1179,7 +1188,7 @@ public class CPHInline operations.ClearCompletedTasks(); operations.Cleanup(false); SaveTasks(); - Broadcast(new { mode = "refresh" }, null); + Broadcast(new { mode = "cleardone" }, null); Respond(BotResponses.ClearDone); return true; } @@ -1189,7 +1198,7 @@ public class CPHInline operations.FilterToStreamers(GetStreamerUsernames()); operations.Cleanup(false); SaveTasks(); - Broadcast(new { mode = "refresh" }, null); + Broadcast(new { mode = "clearns" }, null); Respond(BotResponses.ClearNotStreamer); return true; } diff --git a/widgets/horizontal/README.md b/widgets/horizontal/README.md index f49b08a..c8eb6d8 100644 --- a/widgets/horizontal/README.md +++ b/widgets/horizontal/README.md @@ -6,7 +6,7 @@ Websocket server running is required for browser source to work. -> ![websocket](./images/websocket.png) +> ![websocket](../shared/images/websocket.png) 1. Streamer.Bot -> Servers/Clients -> Websocket Server 2. Auto Start: `ON`; Click on `Start Server` diff --git a/widgets/horizontal/index.html b/widgets/horizontal/index.html index 6fc7ee0..318dfcf 100644 --- a/widgets/horizontal/index.html +++ b/widgets/horizontal/index.html @@ -3,11 +3,11 @@ - + - - - + + + diff --git a/widgets/horizontal/scripts/emotes.js b/widgets/horizontal/scripts/emotes.js deleted file mode 100644 index c6eafb9..0000000 --- a/widgets/horizontal/scripts/emotes.js +++ /dev/null @@ -1,273 +0,0 @@ -"use strict"; - -class EmoteManager { - #emotes = new Map(); - #channelName = ""; - #channelId = ""; - #providers = ["7tv", "bttv", "ffz"]; - #size = "1x"; - #loaded = false; - #cacheTTL = 24 * 60 * 60 * 1000; - #CACHE_KEY = "emote-cache-v1"; - #pattern = null; - #patternSize = 0; - - constructor(config = {}) { - this.#channelName = config.channelName; - this.#channelId = config.channelId; - if (config.providers) this.#providers = config.providers; - if (config.size) this.#size = config.size; - } - - get loaded() { - return this.#loaded; - } - - get emoteCount() { - return this.#emotes.size; - } - - get providers() { - return [...this.#providers]; - } - - getEmote(name) { - return this.#emotes.get(name) || null; - } - - #buildPattern() { - if (this.#emotes.size === 0) { - this.#pattern = null; - this.#patternSize = 0; - return; - } - - if (this.#pattern && this.#emotes.size === this.#patternSize) return; - - const sorted = [...this.#emotes.keys()].sort( - (a, b) => b.length - a.length, - ); - const escaped = sorted.map((n) => - n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), - ); - this.#pattern = new RegExp( - `(? { - const emote = this.#emotes.get(match); - if (!emote) return match; - console.log(emote); - return `${match}`; - }); - } - - async init() { - const cached = this.#loadCache(); - if (cached) { - this.#emotes = new Map(Object.entries(cached.emotes)); - this.#loaded = true; - this.#patternSize = 0; - return; - } - - await this.#fetchAll(); - this.#loaded = true; - this.#patternSize = 0; - this.#saveCache(); - } - - async forceRefresh() { - this.#emotes.clear(); - this.#patternSize = 0; - await this.#fetchAll(); - this.#loaded = true; - this.#patternSize = 0; - this.#saveCache(); - } - - async #fetchAll() { - const fetchers = []; - if (this.#providers.includes("7tv")) fetchers.push(this.#fetch7TV()); - if (this.#providers.includes("bttv")) fetchers.push(this.#fetchBTTV()); - if (this.#providers.includes("ffz")) fetchers.push(this.#fetchFFZ()); - await Promise.allSettled(fetchers); - } - - async #fetch7TV() { - try { - const globalResp = await fetch( - "https://7tv.io/v3/emote-sets/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (globalData.emotes) { - for (const emote of globalData.emotes) { - this.#add7TVEmote(emote); - } - } - - if (this.#channelId) { - const userResp = await fetch( - `https://7tv.io/v3/users/twitch/${this.#channelId}`, - ); - if (!userResp.ok) return; - const userData = await userResp.json(); - if (userData.emote_set?.emotes) { - for (const emote of userData.emote_set.emotes) { - this.#add7TVEmote(emote); - } - } - } - } catch (e) { - console.warn("7TV emote fetch failed:", e.message); - } - } - - #add7TVEmote(emote) { - const entry = emote.data || emote; - const id = entry.id || emote.id; - const name = entry.name || emote.name; - if (!id || !name) return; - const nameLower = name; - const host = entry.host.url; - this.#emotes.set(nameLower, { - url: `https:${host}/${this.#size}.webp`, - provider: "7tv", - animated: entry.animated || false, - }); - } - - async #fetchBTTV() { - try { - const globalResp = await fetch( - "https://api.betterttv.net/3/cached/emotes/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (Array.isArray(globalData)) { - for (const emote of globalData) { - this.#emotes.set(emote.code, { - url: `https://cdn.betterttv.net/emote/${emote.id}/${this.#size}`, - provider: "bttv", - animated: emote.imageType === "gif", - }); - } - } - - if (this.#channelId) { - const userResp = await fetch( - `https://api.betterttv.net/3/cached/users/twitch/${this.#channelId}`, - ); - if (!userResp.ok) return; - const userData = await userResp.json(); - const allEmotes = [ - ...(userData.channelEmotes || []), - ...(userData.sharedEmotes || []), - ]; - for (const emote of allEmotes) { - this.#emotes.set(emote.code, { - url: `https://cdn.betterttv.net/emote/${emote.id}/${this.#size}`, - provider: "bttv", - animated: emote.imageType === "gif", - }); - } - } - } catch (e) { - console.warn("BTTV emote fetch failed:", e.message); - } - } - - async #fetchFFZ() { - try { - const globalResp = await fetch( - "https://api.frankerfacez.com/v1/set/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (globalData.sets) { - for (const setId in globalData.sets) { - const set = globalData.sets[setId]; - for (const emote of set.emoticons || []) { - if (emote.modifier) continue; - this.#emotes.set(emote.name, { - url: emote.urls[this.#toFFZSize(this.#size)], - provider: "ffz", - animated: false, - }); - } - } - } - - const ffzId = this.#channelName || this.#channelId; - if (ffzId) { - const roomUrl = this.#channelId - ? `https://api.frankerfacez.com/v1/room/id/${this.#channelId}` - : `https://api.frankerfacez.com/v1/room/${this.#channelName}`; - const roomResp = await fetch(roomUrl); - if (!roomResp.ok) return; - const roomData = await roomResp.json(); - if (roomData.sets) { - for (const setId in roomData.sets) { - const set = roomData.sets[setId]; - for (const emote of set.emoticons || []) { - if (emote.modifier) continue; - this.#emotes.set(emote.name, { - url: emote.urls[this.#toFFZSize(this.#size)], - provider: "ffz", - animated: false, - }); - } - } - } - } - } catch (e) { - console.warn("FFZ emote fetch failed:", e.message); - } - } - - #toFFZSize(size) { - switch (size) { - case "3x": - case "4x": - return "4"; - case "2x": - return "2"; - default: - return "1"; - } - } - - #saveCache() { - try { - const cache = { - timestamp: Date.now(), - channelId: this.#channelId, - emotes: Object.fromEntries(this.#emotes), - }; - localStorage.setItem(this.#CACHE_KEY, JSON.stringify(cache)); - } catch (e) {} - } - - #loadCache() { - try { - const raw = localStorage.getItem(this.#CACHE_KEY); - if (!raw) return null; - const cache = JSON.parse(raw); - if (cache.channelId !== this.#channelId) return null; - if (Date.now() - cache.timestamp > this.#cacheTTL) return null; - return cache; - } catch (e) { - return null; - } - } -} diff --git a/widgets/horizontal/scripts/streamerbot.js b/widgets/horizontal/scripts/streamerbot.js deleted file mode 100644 index 51a2b9c..0000000 --- a/widgets/horizontal/scripts/streamerbot.js +++ /dev/null @@ -1,200 +0,0 @@ -// STREAMER.BOT SETTINGS - -const client = new StreamerbotClient({ - host: configs.streamerBotSettings.host, - port: configs.streamerBotSettings.port, - endpoint: configs.streamerBotSettings.endpoint, - onConnect: onConnect, - onDisconnect: onDisconnect, - onError: onError, -}); - -function getAllLocalstorage() { - const allLocalStorage = {}; - - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - allLocalStorage[key] = localStorage.getItem(key); - } - - return JSON.stringify(allLocalStorage); -} - -client.on("General.Custom", (data) => onCustom(data)); -if (configs.userColorSettings.autoUserColor) { - client.on("Twitch.ChatMessage", (data) => onChatMessage(data)); - client.on("Kick.ChatMessage", (data) => onChatMessage(data)); -} - -let taskList; -let userColors = {}; - -function parseHexColor(hex) { - if (typeof hex !== "string") return null; - const s = hex.trim(); - const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s); - if (!m) return null; - let h = m[1].toLowerCase(); - if (h.length === 3) { - h = h - .split("") - .map((c) => c + c) - .join(""); - } - const r = parseInt(h.slice(0, 2), 16); - const g = parseInt(h.slice(2, 4), 16); - const b = parseInt(h.slice(4, 6), 16); - return { r, g, b }; -} - -function relativeLuminance({ r, g, b }) { - const toLinear = (v) => { - const s = v / 255; - return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); - }; - const R = toLinear(r); - const G = toLinear(g); - const B = toLinear(b); - return 0.2126 * R + 0.7152 * G + 0.0722 * B; -} - -async function onChatMessage(data) { - let userColor = data.data.user.color; // hex colour #FF69B4 - - if (userColor != undefined || userColor != "undefined") { - // update localstorage - // get id: platform-userID - let userId = data.data.user.id; - let key = `twitch-${userId}`; - - localStorage.setItem(`${key}-color`, userColor); - userColors[`${key}-color`] = userColor; - } - - return; -} - -function onDisconnect() { - showConnectionError("Connection Failed: Unable to connect to Streamer.bot"); -} - -function onError(err) { - showConnectionError( - "Connection Failed: " + (err?.message || "Unknown error"), - ); -} - -function showConnectionError(message) { - // Remove existing popup if any - const existing = document.getElementById("connection-error"); - if (existing) existing.remove(); - - const popup = document.createElement("div"); - popup.id = "connection-error"; - popup.textContent = message; - Object.assign(popup.style, { - position: "fixed", - top: "20px", - left: "50%", - transform: "translateX(-50%)", - background: "#e53935", - color: "#fff", - padding: "12px 24px", - borderRadius: "8px", - fontFamily: "'Fredoka', sans-serif", - fontSize: "1.1rem", - fontWeight: "700", - zIndex: "9999", - boxShadow: "0 4px 12px rgba(0,0,0,0.4)", - textAlign: "center", - }); - document.body.appendChild(popup); - - // Auto-dismiss after 5 seconds - setTimeout(() => { - popup.animate([{ opacity: 1 }, { opacity: 0 }], { - duration: 300, - fill: "forwards", - }).onfinish = () => popup.remove(); - }, 5000); -} - -async function refresh() { - const response = await client.getGlobal("rython-task-bot", true); - console.log(response); - - if (response.status !== "ok" || !response.variable?.value) return; - - const users = JSON.parse(response.variable.value); - const sections = transformToSections(users); - - taskList.load(sections); -} - -// LOAD TASK LIST -async function onConnect() { - taskList = new TaskList(".task-panel"); - - if (configs.emoteSettings.enabled) { - let broadcaster = await client.getBroadcaster(); - - console.log(broadcaster); - - let broadcasterName = - broadcaster.platforms.twitch?.broadcastUser ?? - broadcaster.platforms.youtube?.broadcastUser ?? - broadcaster.platforms.kick?.broadcastUser; - - let broadcasterId = - broadcaster.platforms.twitch?.broadcastUserId ?? - broadcaster.platforms.youtube?.broadcastUserId ?? - broadcaster.platforms.kick?.broadcastUserId; - - window.emoteManager = new EmoteManager({ - channelName: broadcasterName, - channelId: broadcasterId, - providers: configs.emoteSettings.providers, - size: configs.emoteSettings.size, - }); - - window.emoteManager.init().then(() => { - if (taskList) { - taskList.load(taskList.getData()); - } - }); - } - - refresh(); -} - -function transformToSections(users) { - return Object.entries(users).map(([userId, userData]) => ({ - id: userId, - title: userData.Username, - tasks: userData.Tasks.map((task) => ({ - text: task.Name, - done: task.Completed, - focused: task.Focused, - })), - })); -} - -// Update task list action by action -function onCustom(payload) { - const data = payload.data; - if (!data.source && data.source != "rython-task-bot") { - return; - } - if (!taskList) return; - const body = data.body; - const id = data.id; - const username = data.username; - - switch (body.mode) { - case "refresh": - refresh(); - break; - default: - break; - } -} diff --git a/widgets/horizontal/scripts/tasklist-view.js b/widgets/horizontal/scripts/tasklist-view.js deleted file mode 100644 index edff58c..0000000 --- a/widgets/horizontal/scripts/tasklist-view.js +++ /dev/null @@ -1,591 +0,0 @@ -// Task list view - -class TaskList { - #data = []; - #firstRender = true; - #pendingRemovals = 0; - - #scroll = { - offset: 0, - contentW: 0, - viewportW: 0, - speed: 50, - raf: null, - lastT: 0, - active: false, - wantStop: false, - }; - - #els = {}; - - #ANIM_DURATION = 400; - #ANIM_EASING = "cubic-bezier(0.22, 1, 0.36, 1)"; - - #parseHexColor(hex) { - if (typeof hex !== "string") return null; - const s = hex.trim(); - const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s); - if (!m) return null; - let h = m[1].toLowerCase(); - if (h.length === 3) { - h = h - .split("") - .map((c) => c + c) - .join(""); - } - const r = parseInt(h.slice(0, 2), 16); - const g = parseInt(h.slice(2, 4), 16); - const b = parseInt(h.slice(4, 6), 16); - return { r, g, b }; - } - - #relativeLuminance({ r, g, b }) { - const toLinear = (v) => { - const s = v / 255; - return s <= 0.04045 - ? s / 12.92 - : Math.pow((s + 0.055) / 1.055, 2.4); - }; - const R = toLinear(r); - const G = toLinear(g); - const B = toLinear(b); - return 0.2126 * R + 0.7152 * G + 0.0722 * B; - } - - constructor(container) { - const el = - typeof container === "string" - ? document.querySelector(container) - : container; - - this.#els = { - track: el.querySelector(".scroll-track"), - content: el.querySelector(".scroll-content"), - viewport: el.querySelector(".scroll-viewport"), - }; - } - - // ── public API ───────────────────────────────────── - - load(sections) { - this.#data = structuredClone(sections); - this.#render(); - return this; - } - - addSection(section) { - this.#data.push(structuredClone(section)); - this.#render(); - return this; - } - - removeSection(id) { - const i = this.#data.findIndex((s) => s.id === id); - if (i === -1) return this; - this.#data.splice(i, 1); - this.#render(); - return this; - } - - updateSection(id, updater) { - const section = this.#data.find((s) => s.id === id); - if (!section) return this; - updater(section); - this.#render(); - return this; - } - - addTask(sectionId, task, sectionTitle) { - if (!this.#data.find((s) => s.id === sectionId)) { - this.addSection({ - id: sectionId, - title: sectionTitle || sectionId, - tasks: [], - }); - } - - return this.updateSection(sectionId, (s) => { - s.tasks.push(structuredClone(task)); - }); - } - - removeTask(sectionId, taskIndex) { - this.updateSection(sectionId, (s) => { - s.tasks.splice(taskIndex, 1); - }); - this.#data = this.#data.filter((s) => s.tasks.length > 0); - this.#render(); - return this; - } - - editTask(sectionId, taskIndex, newText, userColor) { - return this.updateSection(sectionId, (s) => { - if (s.tasks[taskIndex]) { - s.tasks[taskIndex].text = newText; - } - }); - } - - doneTask(sectionId, taskIndex) { - return this.updateSection(sectionId, (s) => { - if (s.tasks[taskIndex]) { - s.tasks[taskIndex].done = true; - s.tasks[taskIndex].focused = false; - } - }); - } - - undoneTask(sectionId, taskIndex) { - return this.updateSection(sectionId, (s) => { - if (s.tasks[taskIndex]) { - s.tasks[taskIndex].done = false; - } - }); - } - - focusTask(sectionId, taskIndex) { - // unfocus any previously focused task - this.unfocusTask(sectionId); - - return this.updateSection(sectionId, (s) => { - if (s.tasks[taskIndex]) { - s.tasks[taskIndex].focused = true; - } - }); - } - - unfocusTask(sectionId) { - return this.updateSection(sectionId, (s) => { - for (let i = 0; i < s.tasks.length; i++) { - s.tasks[i].focused = false; - } - }); - } - - clearmydone(sectionId) { - this.updateSection(sectionId, (s) => { - s.tasks = s.tasks.filter((t) => !t.done); - }); - this.#data = this.#data.filter((s) => s.tasks.length > 0); - this.#render(); - return this; - } - - cleardone() { - this.#data.forEach((s) => { - s.tasks = s.tasks.filter((t) => !t.done); - }); - this.#data = this.#data.filter((s) => s.tasks.length > 0); - this.#render(); - return this; - } - - getData() { - return structuredClone(this.#data); - } - - get sectionCount() { - return this.#data.length; - } - - get taskCount() { - return this.#data.reduce((sum, s) => sum + s.tasks.length, 0); - } - - get doneCount() { - return this.#data.reduce( - (sum, s) => sum + s.tasks.filter((t) => t.done).length, - 0, - ); - } - - destroy() { - this.#forceStop(); - this.#els.content.innerHTML = ""; - this.#data = []; - this.#firstRender = true; - } - - // ── render ───────────────────────────────────────── - - #render() { - if (this.#firstRender) { - this.#data.forEach((s) => - this.#els.content.appendChild(this.#createSectionEl(s)), - ); - this.#firstRender = false; - } else { - this.#patchContainer(this.#els.content, this.#data, true); - } - - if (this.#pendingRemovals === 0) { - this.#syncScroll(); - } - } - - // ── animations ───────────────────────────────────── - - #animateIn(el) { - el.style.overflow = "hidden"; - - const w = el.scrollWidth; - el.style.width = "0px"; - el.style.opacity = "0"; - - requestAnimationFrame(() => { - const anim = el.animate( - [ - { - width: "0px", - opacity: 0, - transform: "translateX(-8px)", - }, - { - width: w + "px", - opacity: 1, - transform: "translateX(0)", - }, - ], - { - duration: this.#ANIM_DURATION, - easing: this.#ANIM_EASING, - fill: "forwards", - }, - ); - - anim.onfinish = () => { - el.style.width = ""; - el.style.opacity = ""; - el.style.overflow = ""; - el.style.transform = ""; - anim.cancel(); - this.#syncScroll(); - }; - }); - } - - #animateRemove(el) { - this.#pendingRemovals++; - const w = el.scrollWidth; - - const anim = el.animate( - [ - { width: w + "px", opacity: 1, transform: "translateX(0)" }, - { width: "0px", opacity: 0, transform: "translateX(-8px)" }, - ], - { - duration: this.#ANIM_DURATION, - easing: this.#ANIM_EASING, - fill: "forwards", - }, - ); - - anim.onfinish = () => { - el.remove(); - this.#pendingRemovals--; - - if (this.#pendingRemovals === 0) { - this.#syncScroll(); - } - }; - } - - #animateStrikethrough(el) { - el.animate( - [ - { opacity: 0.5, transform: "scale(0.98)" }, - { opacity: 1, transform: "scale(1)" }, - ], - { duration: 250, easing: "ease-out" }, - ); - } - - // ── dom helpers ──────────────────────────────────── - - #parseTaskText(text) { - if (window.emoteManager && window.emoteManager.loaded) { - return window.emoteManager.parseText(text); - } - return text; - } - - #createTaskEl(task, index) { - const div = document.createElement("div"); - div.className = - "task" + - (task.done ? " done" : "") + - (task.focused ? " focused" : ""); - div.dataset.text = task.text; - const numberSpan = document.createElement("span"); - numberSpan.className = "task-number"; - numberSpan.textContent = `${index + 1}.`; - - const textSpan = document.createElement("span"); - textSpan.className = "task-text"; - textSpan.innerHTML = this.#parseTaskText(task.text); - - div.replaceChildren(numberSpan, textSpan); - return div; - } - - #createSectionEl(section) { - const div = document.createElement("div"); - div.className = "section"; - div.dataset.key = section.id; - if (section.title) { - const t = document.createElement("div"); - t.className = "section-title"; - t.textContent = section.title; - let color = - section.color ?? localStorage.getItem(`${section.id}-color`); - if ( - configs.userColorSettings.autoUserColor && - color != undefined && - color != "undefined" && - color != null - ) { - t.style.setProperty("--user-color", color); - t.classList.add("has-user-color"); - } - - div.appendChild(t); - } - section.tasks.forEach((task, i) => - div.appendChild(this.#createTaskEl(task, i)), - ); - return div; - } - - // ── patching ─────────────────────────────────────── - - #patchTasks(sectionEl, tasks, animate) { - const existing = [...sectionEl.querySelectorAll(":scope > .task")]; - - tasks.forEach((task, i) => { - if (i < existing.length) { - const el = existing[i]; - const wantClass = - "task" + - (task.done ? " done" : "") + - (task.focused ? " focused" : ""); - if (el.className !== wantClass) { - el.className = wantClass; - if (animate) this.#animateStrikethrough(el); - } - if (el.dataset.text !== task.text) { - el.dataset.text = task.text; - const textEl = - el.querySelector(".task-text") || - el.querySelector("span:last-child"); - textEl.innerHTML = this.#parseTaskText(task.text); - } - el.querySelector(".task-number").textContent = `${i + 1}.`; - - // Update color if changed - if (task.color != undefined && task.color != "undefined") { - el.style.setProperty("--user-color", task.color); - el.classList.add("has-user-color"); - } else { - el.style.removeProperty("--user-color"); - el.classList.remove("has-user-color"); - } - } else { - const newEl = this.#createTaskEl(task, i); - sectionEl.appendChild(newEl); - if (animate) this.#animateIn(newEl); - } - }); - - for (let i = existing.length - 1; i >= tasks.length; i--) { - if (animate) { - this.#animateRemove(existing[i]); - } else { - existing[i].remove(); - } - } - } - - #patchContainer(container, sections, animate) { - const oldMap = new Map(); - container.querySelectorAll(":scope > .section").forEach((el) => { - oldMap.set(el.dataset.key, el); - }); - - let cursor = container.firstElementChild; - - sections.forEach((section) => { - const key = section.id; - const existing = oldMap.get(key); - - if (existing) { - this.#patchTasks(existing, section.tasks, animate); - if (existing !== cursor) { - container.insertBefore(existing, cursor); - } else { - cursor = cursor.nextElementSibling; - } - oldMap.delete(key); - } else { - const newEl = this.#createSectionEl(section); - container.insertBefore(newEl, cursor); - if (animate) this.#animateIn(newEl); - } - }); - - oldMap.forEach((el) => { - if (animate) { - this.#animateRemove(el); - } else { - el.remove(); - } - }); - } - - // ── scroll ───────────────────────────────────────── - - #tick = (now) => { - const s = this.#scroll; - const dt = (now - s.lastT) / 1000; - s.lastT = now; - - if (dt < 0.2) { - s.contentW = this.#els.content.scrollWidth; - s.offset += s.speed * dt; - - if (s.contentW > 0 && s.offset >= s.contentW) { - s.offset -= s.contentW; - - if (s.wantStop) { - s.wantStop = false; - this.#forceStop(); - return; - } - } - - this.#els.track.style.transform = `translateX(${-s.offset}px)`; - } - - s.raf = requestAnimationFrame(this.#tick); - }; - - #startScroll() { - const s = this.#scroll; - s.wantStop = false; - if (s.active) return; - s.active = true; - s.lastT = performance.now(); - s.raf = requestAnimationFrame(this.#tick); - } - - #requestStop() { - if (!this.#scroll.active) return; - this.#scroll.wantStop = true; - } - - #forceStop() { - const s = this.#scroll; - s.active = false; - s.wantStop = false; - cancelAnimationFrame(s.raf); - s.raf = null; - s.offset = 0; - this.#els.track.style.transform = ""; - - const clone = this.#els.track.querySelector(".scroll-clone"); - if (clone) clone.remove(); - } - - #syncScroll() { - const s = this.#scroll; - s.contentW = this.#els.content.scrollWidth; - s.viewportW = this.#els.viewport.clientWidth; - const needs = s.contentW > s.viewportW; - - let clone = this.#els.track.querySelector(".scroll-clone"); - - if (needs) { - if (!clone) { - clone = this.#els.content.cloneNode(true); - clone.id = ""; - clone.classList.add("scroll-clone"); - this.#els.track.appendChild(clone); - } else { - this.#patchContainer(clone, this.#data, false); - } - if (s.offset >= s.contentW) { - s.offset %= s.contentW; - } - this.#startScroll(); - } else { - if (s.active) { - if (clone) this.#patchContainer(clone, this.#data, false); - this.#requestStop(); - } else { - if (clone) clone.remove(); - } - } - } -} - -// ── usage ────────────────────────────────────────────── - -// const list2 = new TaskList(".task-panel"); - -// list2.load([ -// { -// title: "someone", -// tasks: [ -// { text: "dinner" }, -// { text: "watch bad bunny halftime show" }, -// { text: "tie tf down", done: true }, -// { text: "boy dinner", done: true }, -// { text: "3 hour SOOP" }, -// ], -// }, -// { -// title: "Cape_Codder", -// tasks: [ -// { text: "Part 2", done: true }, -// { text: "Ch 1-2", done: true }, -// ], -// }, -// { -// title: "sunflawer", -// tasks: [ -// { text: "fix walls from home office" }, -// { text: "sand walls zzzsdkjhfsk", done: true }, -// { text: "meal prep" }, -// { text: "buy wrist brace maybe" }, -// ], -// }, -// { -// title: "extra_user1", -// tasks: [ -// { text: "go grocery shopping" }, -// { text: "clean the kitchen", done: true }, -// { text: "respond to emails" }, -// ], -// }, -// ]); - -// demo - -// setTimeout(() => { -// list2.addTask("someone2", { text: "new task just dropped" }); -// }, 1000); - -// setTimeout(() => { -// list2.; -// }, 3000); - -// setTimeout(() => { -// list.toggleTask("sunflawer", 0); -// }, 10000); - -// setTimeout(() => { -// list.removeSection("Cape_Codder"); -// }, 12000); - -// setTimeout(() => { -// list.removeTask("extra_user1", 1); -// }, 14000); diff --git a/widgets/horizontal/images/websocket.png b/widgets/shared/images/websocket.png similarity index 100% rename from widgets/horizontal/images/websocket.png rename to widgets/shared/images/websocket.png diff --git a/widgets/horizontal/lib/streamerbot-client.js b/widgets/shared/lib/streamerbot-client.js similarity index 100% rename from widgets/horizontal/lib/streamerbot-client.js rename to widgets/shared/lib/streamerbot-client.js diff --git a/widgets/vertical/scripts/emotes.js b/widgets/shared/scripts/emotes.js similarity index 100% rename from widgets/vertical/scripts/emotes.js rename to widgets/shared/scripts/emotes.js diff --git a/widgets/vertical/scripts/streamerbot.js b/widgets/shared/scripts/streamerbot.js similarity index 67% rename from widgets/vertical/scripts/streamerbot.js rename to widgets/shared/scripts/streamerbot.js index 6aa5b00..2c09e78 100644 --- a/widgets/vertical/scripts/streamerbot.js +++ b/widgets/shared/scripts/streamerbot.js @@ -9,17 +9,6 @@ const client = new StreamerbotClient({ onError: onError, }); -function getAllLocalstorage() { - const allLocalStorage = {}; - - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - allLocalStorage[key] = localStorage.getItem(key); - } - - return JSON.stringify(allLocalStorage); -} - client.on("General.Custom", (data) => onCustom(data)); if (configs.userColorSettings.autoUserColor) { client.on("Twitch.ChatMessage", (data) => onChatMessage(data)); @@ -29,49 +18,35 @@ if (configs.userColorSettings.autoUserColor) { let taskList; let userColors = {}; -function parseHexColor(hex) { - if (typeof hex !== "string") return null; - const s = hex.trim(); - const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s); - if (!m) return null; - let h = m[1].toLowerCase(); - if (h.length === 3) { - h = h - .split("") - .map((c) => c + c) - .join(""); - } - const r = parseInt(h.slice(0, 2), 16); - const g = parseInt(h.slice(2, 4), 16); - const b = parseInt(h.slice(4, 6), 16); - return { r, g, b }; +function getUserColor(sectionId) { + return ( + userColors[`${sectionId}-color`] ?? + localStorage.getItem(`${sectionId}-color`) + ); } -function relativeLuminance({ r, g, b }) { - const toLinear = (v) => { - const s = v / 255; - return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); - }; - const R = toLinear(r); - const G = toLinear(g); - const B = toLinear(b); - return 0.2126 * R + 0.7152 * G + 0.0722 * B; +function taskColorFromSettings(sectionId) { + const usernameColor = getUserColor(sectionId); + if ( + configs.userColorSettings.autoUserColor && + usernameColor != undefined && + usernameColor != null + ) { + return usernameColor; + } + return undefined; } async function onChatMessage(data) { - let userColor = data.data.user.color; // hex colour #FF69B4 + const userColor = data.data.user.color; - if (userColor != undefined || userColor != "undefined") { - // update localstorage - // get id: platform-userID - let userId = data.data.user.id; - let key = `twitch-${userId}`; + if (userColor != undefined && userColor != "undefined") { + const userId = data.data.user.id; + const key = `twitch-${userId}`; localStorage.setItem(`${key}-color`, userColor); userColors[`${key}-color`] = userColor; } - - return; } function onDisconnect() { @@ -85,7 +60,6 @@ function onError(err) { } function showConnectionError(message) { - // Remove existing popup if any const existing = document.getElementById("connection-error"); if (existing) existing.remove(); @@ -110,7 +84,6 @@ function showConnectionError(message) { }); document.body.appendChild(popup); - // Auto-dismiss after 5 seconds setTimeout(() => { popup.animate([{ opacity: 1 }, { opacity: 0 }], { duration: 300, @@ -121,7 +94,6 @@ function showConnectionError(message) { async function refresh() { const response = await client.getGlobal("rython-task-bot", true); - console.log(response); if (response.status !== "ok" || !response.variable?.value) return; @@ -131,19 +103,18 @@ async function refresh() { taskList.load(sections); } -// LOAD TASK LIST async function onConnect() { taskList = new TaskList(".task-panel"); if (configs.emoteSettings.enabled) { - let broadcaster = await client.getBroadcaster(); + const broadcaster = await client.getBroadcaster(); - let broadcasterName = + const broadcasterName = broadcaster.platforms.twitch?.broadcastUser ?? broadcaster.platforms.youtube?.broadcastUser ?? broadcaster.platforms.kick?.broadcastUser; - let broadcasterId = + const broadcasterId = broadcaster.platforms.twitch?.broadcastUserId ?? broadcaster.platforms.youtube?.broadcastUserId ?? broadcaster.platforms.kick?.broadcastUserId; @@ -177,19 +148,58 @@ function transformToSections(users) { })); } -// Update task list action by action function onCustom(payload) { const data = payload.data; - if (!data.source && data.source != "rython-task-bot") { + if (data.source !== "rython-task-bot") { return; } if (!taskList) return; + const body = data.body; const id = data.id; const username = data.username; switch (body.mode) { - case "refresh": + case "add": { + const taskPayload = { + text: body.task, + done: body.completed, + focused: body.focused, + }; + const color = taskColorFromSettings(id); + if (color) taskPayload.color = color; + taskList.addTask(id, taskPayload, username); + break; + } + case "focus": + taskList.focusTask(id, body.index); + break; + case "edit": + taskList.editTask(id, body.index, body.task, taskColorFromSettings(id)); + break; + case "remove": + taskList.removeTask(id, body.index); + break; + case "done": + taskList.doneTask(id, body.index); + break; + case "undone": + taskList.undoneTask(id, body.index); + break; + case "unfocus": + taskList.unfocusTask(id); + break; + case "admindelete": + taskList.removeSection(body.id); + break; + case "clearmydone": + taskList.clearmydone(id); + break; + case "cleardone": + taskList.cleardone(); + break; + case "clearall": + case "clearns": refresh(); break; default: diff --git a/widgets/vertical/scripts/tasklist-view.js b/widgets/shared/scripts/tasklist-view.js similarity index 100% rename from widgets/vertical/scripts/tasklist-view.js rename to widgets/shared/scripts/tasklist-view.js diff --git a/widgets/streamer-only/README.md b/widgets/streamer-only/README.md index f49b08a..c8eb6d8 100644 --- a/widgets/streamer-only/README.md +++ b/widgets/streamer-only/README.md @@ -6,7 +6,7 @@ Websocket server running is required for browser source to work. -> ![websocket](./images/websocket.png) +> ![websocket](../shared/images/websocket.png) 1. Streamer.Bot -> Servers/Clients -> Websocket Server 2. Auto Start: `ON`; Click on `Start Server` diff --git a/widgets/streamer-only/images/websocket.png b/widgets/streamer-only/images/websocket.png deleted file mode 100644 index 9bfc514bc14b50bdb24b91660a423d65c8db4fab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82494 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 Kb3gg=n|}j^T*xi} diff --git a/widgets/streamer-only/index.html b/widgets/streamer-only/index.html index 6fc7ee0..033836f 100644 --- a/widgets/streamer-only/index.html +++ b/widgets/streamer-only/index.html @@ -3,11 +3,11 @@ - + - + - + diff --git a/widgets/streamer-only/lib/streamerbot-client.js b/widgets/streamer-only/lib/streamerbot-client.js deleted file mode 100644 index 1f1ad44..0000000 --- a/widgets/streamer-only/lib/streamerbot-client.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";var Streamerbot=(()=>{var W=Object.create;var p=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var D=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var O=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),q=(n,e)=>{for(var t in e)p(n,t,{get:e[t],enumerable:!0})},E=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of U(e))!H.call(n,o)&&o!==t&&p(n,o,{get:()=>e[o],enumerable:!(r=L(e,o))||r.enumerable});return n};var M=(n,e,t)=>(t=n!=null?W(D(n)):{},E(e||!n||!n.__esModule?p(t,"default",{value:n,enumerable:!0}):t,n)),B=n=>E(p({},"__esModule",{value:!0}),n);var G=O((Q,P)=>{"use strict";P.exports=function(){throw new Error("ws does not work in the browser. Browser clients must use the native WebSocket object")}});var _={};q(_,{Client:()=>l});var m=class{constructor(e={}){this.logLevels={verbose:0,debug:1,info:2,warn:3,error:4,none:5};this.level=e.level||"info",this.customLogger=e.customLogger}setLevel(e){this.level=e}setCustomLogger(e){this.customLogger=e}verbose(...e){this.log("verbose",...e)}debug(...e){this.log("debug",...e)}info(...e){this.log("info",...e)}warn(...e){this.log("warn",...e)}error(...e){this.log("error",...e)}log(e,...t){if(!(this.logLevels[e]y.getRandomValues(n);function C(n="req"){return`sb:client:${n}:${Date.now()}-${R(new Uint32Array(12))[0]}`}function k(n){let e;return n.code==1e3?e="Connection closed.":n.code==1001?e='Endpoint is "going away".':n.code==1002?e="Connection closed due to a protocol error.":n.code==1003||n.code==1007||n.code==1008||n.code==1010?e="Bad request.":n.code==1004?e="Reserved":n.code==1005?e="Missing status code.":n.code==1006?e="The connection was closed abnormally.":n.code==1009?e="Message size limit exceeded.":n.code==1011?e="Server terminated connection because due to unexpected condition.":n.code==1015?e="TLS handshake failure":e="Unknown error",e}async function h(n,e){let{timeout:t,message:r="Operation timed out.",controller:o}=e,s;return await Promise.race([new Promise((i,a)=>{s=setTimeout(()=>(o.abort(),console.debug("[withTimeout] timeout reached",e),a(new Error(r))),t),e.signal?.addEventListener("abort",()=>{clearTimeout(s),o?.abort(),a(new Error("Operation aborted."))},{once:!0})}),n]).finally(()=>{clearTimeout(s),o.abort()})}async function S(n){let e=new TextEncoder().encode(n),t=await T.digest("SHA-256",e),o=Array.from(new Uint8Array(t)).map(s=>s.toString(16).padStart(2,"0")).join("");return I(o)}function I(n){let e=new Uint8Array(n.match(/.{1,2}/g).map(r=>parseInt(r,16)));return btoa(String.fromCharCode.apply(null,Array.from(e)))}function v({timeout:n=1e4,addEventListener:e,removeEventListener:t}){let r=C("res"),o=new AbortController,s=o.signal,i=new Promise((a,c)=>{let d=b=>{let f=b?.data;f?.eventName===r&&(o.abort(),a(f?.args))};e("Custom.Event",d);let u=setTimeout(()=>{o.abort(),c(new Error("Timed out waiting for Custom Event"))},n);s.addEventListener("abort",()=>{clearTimeout(u),t(b=>b.events?.includes("Custom.Event")&&b.callback===d)},{once:!0})});return{responseId:r,promise:i,controller:o}}var A={scheme:"ws",host:"127.0.0.1",port:8080,endpoint:"/",immediate:!0,autoReconnect:!0,retries:-1,subscribe:{},logger:w,logLevel:"info"},l=class{constructor(e=A){this._authEnabled=!1;this._authenticated=!1;this.listeners=[];this.subscriptions={};this._explicitlyClosed=!1;this._retried=0;this._connectController=new AbortController;this._reconnectTimeout=void 0;this.options={...A,...e},this.logger=this.options.logger||null,this.logger&&this.options.logLevel&&this.logger.setLevel(this.options.logLevel),this.options.immediate===!0&&this.connect().catch(t=>this.logger?.warn("Failed to connect:",t))}get authenticated(){return!!this.socket&&this.socket.readyState===this.socket.OPEN&&this._authenticated}get ready(){return!this.socket||this.socket.readyState!==this.socket.OPEN||this._authEnabled&&!this._authenticated?!1:!!this.info&&!!this.version}async connect(e=1e4){if(this.socket?.readyState!==this.socket?.CLOSED)try{await this.disconnect()}catch{}this._explicitlyClosed=!1,this._connectController.abort(),this._connectController=new AbortController;let t=new AbortController;return this._connectController.signal.addEventListener("abort",()=>{t.abort()},{once:!0}),await h(new Promise(async(r,o)=>{try{this.options.password&&(this._authEnabled=!0);let s=`${this.options.scheme}://${this.options.host}:${this.options.port}${this.options.endpoint}`;this.logger?.debug("Connecting to Streamer.bot WebSocket server at",s,this._authEnabled?"with authentication":""),this.socket=globalThis?.process?.versions?.node?new(await Promise.resolve().then(()=>M(G(),1))).WebSocket(s):new WebSocket(s),this.socket.onmessage=this.onMessage.bind(this),this.socket.onopen=this.onOpen.bind(this),this.socket.onclose=this.onClose.bind(this),this.socket.onerror=this.onError.bind(this),this.socket.addEventListener("open",()=>{if(!this.socket)return o(new Error("WebSocket not initialized"));r()},{signal:t.signal}),this.socket.addEventListener("close",()=>o(new Error("WebSocket closed")),{once:!0})}catch(s){try{await this.disconnect(),this?.options?.onError?.(s)}catch(i){this.logger?.warn("Error invoking onError handler",i)}o(s)}}),{timeout:e,message:"WebSocket connection timeout exceeded",controller:t})}async disconnect(e=1e3,t=1e3){if(this._explicitlyClosed=!0,this._connectController.abort(),this._reconnectTimeout&&clearTimeout(this._reconnectTimeout),!this.socket||this.socket.readyState===this.socket.CLOSED)return;let r=new AbortController,o=r.signal;return await h(new Promise((s,i)=>{if(this.socket?.addEventListener("close",()=>{this.logger?.debug("Disconnected from Streamer.bot WebSocket server"),s()},{signal:o}),this.socket?.readyState!==this.socket?.CLOSING)try{this.socket?.close(e)}catch(a){i(a)}}),{timeout:t,message:"Timeout exceeded while closing connection",controller:r})}async handshake(){if(!this.socket)throw new Error("WebSocket not initialized");let e=new AbortController,{signal:t}=e;this._connectController.signal.addEventListener("abort",()=>{e.abort()},{once:!0,signal:t});let r=await h(new Promise((o,s)=>{this.socket?.addEventListener("message",async i=>{if(!("data"in i)||!i.data||typeof i.data!="string"){this.logger?.debug("Unknown message received",i);return}try{let a=JSON.parse(i.data);a&&"info"in a&&o(a)}catch(a){this.logger?.warn("Invalid JSON payload received",i.data),s(a)}},{signal:t})}),{timeout:5e3,message:"Handshake timeout exceeded",controller:e});if(!r||!("info"in r))throw new Error("Handshake failed (invalid payload)");if("request"in r&&r?.request==="Hello"&&r.authentication)return await this.authenticate(r);if(r.info&&!r.authentication){this.logger?.debug("Connected to Streamer.bot WebSocket server",r.info),this.info=r.info,this.version=r.info.version;return}throw new Error("Handshake failed (unknown)")}async authenticate(e){if(!this._authEnabled||!this.options.password){if(this.logger?.debug("No password provided for authentication. Checking if auth is enforced for all requests..."),(await this.getInfo()).status==="ok"){this._authenticated=!1,this.version=e.info.version,this.info=e.info;return}throw await this.disconnect(),new Error("Authentication required")}if(!e.authentication)throw this.logger?.debug("Missing authentication payload"),await this.disconnect(),new Error("Invalid authentication payload");this.logger?.debug("Authenticating with Streamer.bot WebSocket server...");let{salt:t,challenge:r}=e?.authentication,o=await S(`${this.options.password}${t}`),s=await S(`${o}${r}`);if((await this.request({request:"Authenticate",authentication:s})).status==="ok")this._authenticated=!0,this.version=e.info.version,this.info=e.info;else throw await this.disconnect(),new Error("Authentication failed")}async onOpen(){this._retried=0,this._reconnectTimeout&&clearTimeout(this._reconnectTimeout);try{this._authEnabled||this.getInfo().catch(()=>this.logger?.debug("Failed to fetch Streamer.bot instance info")),await this.handshake(),this.version&&this.info&&(this.logger?.debug(`Connected to Streamer.bot: v${this.version} (${this.info.name})`),await this.updateSupportedEvents(),this?.options?.onConnect?.(this.info))}catch(e){return this.logger?.warn("Failed handshake with Streamer.bot",e),this.options?.onError?.(e instanceof Error?e:new Error("Failed handshake with Streamer.bot")),await this.disconnect()}try{if(this.options.subscribe==="*"||typeof this.options.subscribe=="object"&&!Array.isArray(this.options.subscribe)&&Object.keys(this.options.subscribe??{}).length)this.logger?.debug("Subscribing to initial events from options:",this.options.subscribe),await this.subscribe(this.options.subscribe);else if(typeof this.options.subscribe=="string"||Array.isArray(this.options.subscribe)){this.logger?.debug("Subscribing to initial events from options:",this.options.subscribe);let e=await this.getSubscriptionsFromEventStrings(this.options.subscribe);this.logger?.debug("Parsed subscriptions from options:",e),e&&await this.subscribe(e)}if(this.listeners.length){let e=await this.getSubscriptionsFromListeners();await this.subscribe(e)}this.logger?.verbose("Subscribed to requested events",this.subscriptions,this.listeners)}catch(e){this.logger?.warn("Error subscribing to requested events",e)}}onClose(e){this._connectController.abort();try{(e.type==="error"||!e.wasClean)&&this.options.onError&&this?.options?.onError(new Error(k(e))),this?.options?.onDisconnect?.()}catch(t){this.logger?.warn("Error invoking user-provided onDisconnect handler",t)}if(this._explicitlyClosed||!this.options.autoReconnect)return this.logger?.debug("Cleaning up..."),this.cleanup();this._retried+=1,typeof this.options.retries=="number"&&(this.options.retries<0||this._retried{if(!(this.socket&&this.socket.readyState!==this.socket.CLOSED)){this.logger?.debug(`Reconnecting... (attempt ${this._retried})`);try{await this.connect(1e4)}catch(t){this._retried&&this.logger?.warn(`Failed to reconnect (attempt ${this._retried-1})`,t)}}},Math.min(3e4,this._retried*1e3))):(this.logger?.debug("Auto-reconnect limit reached. Cleaning up..."),this.cleanup())}async onMessage(e){if(!e.data||typeof e.data!="string"){this.logger?.debug("Unknown message received",e);return}let t;try{t=JSON.parse(e.data)}catch(r){this.logger?.warn("Invalid JSON payload received",e.data,r);return}this.logger?.verbose("RECV",t);try{this.options.onData&&this?.options?.onData(t)}catch(r){this.logger?.warn("Error occurred within user-provided onData callback",r)}if(t?.event?.source&&t?.event?.type){for(let r of this.listeners)if(r.events?.length&&r.events.find(o=>o==="*"||o===`${t?.event?.source}.${t?.event?.type}`||o.split(".",2)?.[1]==="*"&&o.split(".",2)?.[0]===t?.event?.source))try{r.callback(t)}catch(o){this.logger?.warn(`Error occurred within user-provided event callback (${r.events})`,o)}}}onError(e){this.logger?.debug("WebSocket onError",e),this.socket&&this.socket.readyState!==this.socket.OPEN&&this._connectController.abort();try{this?.options?.onError?.(new Error("WebSocket Error"))}catch(t){this.logger?.warn("Error occurred within user-provided onError callback",t)}}cleanup(){this.socket&&(this.socket.onopen=null,this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket=void 0),this.listeners=[],this._retried=0,this._connectController.abort(),this._reconnectTimeout&&clearTimeout(this._reconnectTimeout)}send(e){this.socket?.send(JSON.stringify(e))}async request(e,t="",r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");t||(t=C());let o=new AbortController,s=o.signal;this._connectController.signal.addEventListener("abort",()=>{o.abort()},{once:!0,signal:s});let i=await h(new Promise((a,c)=>{this.socket?.addEventListener("message",d=>{if(!("data"in d)||!d.data||typeof d.data!="string"){this.logger?.debug("Unknown message received",d.data);return}try{let u=JSON.parse(d?.data);if(u?.id===t)return this.logger?.verbose(`RECV :: ${e.request}`,u),a(u)}catch(u){this.logger?.warn("Invalid JSON payload received",d.data),c(u)}},{signal:s}),this.logger?.verbose(`SEND :: ${e.request}`,{...e,id:t}),this.send({...e,id:t})}),{timeout:r,message:"Request timed out",controller:o,signal:s});if(i?.status==="ok"){try{this.options.onData&&this?.options?.onData(i)}catch(a){this.logger?.warn("Error invoking onData handler",a)}return{event:{source:"Request",type:e.request??"Unknown"},...i}}throw new Error("Request failed")}async on(e,t){try{if(!e)return;let r={events:[e],callback:t};if(this.listeners.push(r),this.ready){let o=await this.getSubscriptionsFromListeners([r]);await this.subscribe(o)}this.logger?.debug(`Added event listener for "${e}"`)}catch(r){this.logger?.warn(`Failed adding event listener for "${e}"`,r)}}async updateSupportedEvents(){if(this.ready)try{let e=await this.getEvents();if(e.status!=="ok"||!e.events)throw new Error(e.status);this.supportedEvents=e.events,this.logger?.debug(`Successfully fetched supported event types for Streamer.bot v${this.version}`)}catch(e){this.logger?.warn("Failed to fetch supported events from Streamer.bot, falling back to stored events type.",e),this.supportedEvents=g}}async getSupportedEvents(){return this.supportedEvents||(this.logger?.warn("Supported event types not yet initialized, fetching from Streamer.bot instance..."),await this.updateSupportedEvents()),this.supportedEvents??g}getEventsFromListeners(e){return(e??this.listeners).reduce((t,r)=>(r.events.forEach(o=>{t[o]||(t[o]=[]),t[o].push(r.callback)}),t),{})}async getSubscriptionsFromListeners(e){let t=this.getEventsFromListeners(e);return this.getSubscriptionsFromEventStrings(Object.keys(t))}async getSubscriptionsFromEventStrings(e){let t={};typeof e=="string"&&(e=[e]);for(let r of e){let o=await this.parseEventString(r);if(o)for(let s of o){let{source:i,eventTypes:a}=s,c=new Set([...t[i]??[],...a]);t[i]=[...c]}}return t}async parseEventString(e){let t=await this.getSupportedEvents();if(!e||typeof e!="string"){this.logger?.warn(`Invalid event subscription requested "${e}"`);return}if(e==="*")return Object.keys(t).map(r=>{let o=r,s=t[o]??[];return{source:o,eventTypes:s}});{let[r,o]=e.split(".",2);if(!r||!o||!(r in t)){this.logger?.warn(`Invalid event subscription requested "${e}"`);return}let s=r,i=o;if(i)return[{source:s,eventTypes:i==="*"?t[s]:[i]}];this.logger?.warn(`Invalid event type requested "${e}"`);return}}async subscribe(e){let t=await this.getSupportedEvents();e==="*"&&(e=t);for(let r in e){if(!r||r==="err")continue;if(!(r in t)){this.logger?.warn(`Attempted to subscribe to empty or unknown event source: "${r}"`,Object.keys(e));continue}let o=r,s=e[o]??[];if(s&&s.length){let i=new Set([...this.subscriptions[o]??[],...s]);this.subscriptions[o]=[...i]}}return Object.keys(this.subscriptions).length===0?(this.logger?.warn("No valid events to subscribe to. Please provide valid event sources and types."),{id:"invalid",status:"error",error:"No valid events to subscribe to"}):await this.request({request:"Subscribe",events:this.subscriptions})}async unsubscribe(e){let t=await this.getSupportedEvents();e==="*"&&(e=t);for(let r in e){if(r===void 0||!Object.keys(t).includes(r))continue;let o=r,s=e[o];if(s&&s.length)for(let i of s)i&&this.subscriptions[o]?.filter&&(this.subscriptions[o]=this.subscriptions[o])?.filter(a=>i!==a)}return await this.request({request:"UnSubscribe",events:e})}async getEvents(){return await this.request({request:"GetEvents"})}async getActions(){return await this.request({request:"GetActions"})}async doAction(e,t,r){if(r?.customEventResponse)return this.doActionWithCustomEventResponse(e,t);let o,s;return typeof e=="string"?o=e:(o=e.id,s=e.name),await this.request({request:"DoAction",action:{id:o,name:s},args:t})}async doActionWithCustomEventResponse(e,t={},r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");let{responseId:o,promise:s,controller:i}=v({timeout:r,addEventListener:(c,d)=>this.on(c,d),removeEventListener:c=>{this.listeners=this.listeners.filter(d=>!c(d))}}),a={...t,sbClientResponse:o};try{let c=await this.doAction(e,a),d=await s;return{...c,customEventResponseArgs:d}}catch(c){throw i.signal.aborted||i.abort(),c}}async getBroadcaster(){return await this.request({request:"GetBroadcaster"})}async getMonitoredYouTubeBroadcasts(){return await this.request({request:"GetMonitoredYouTubeBroadcasts"})}async getCredits(){return await this.request({request:"GetCredits"})}async testCredits(){return await this.request({request:"TestCredits"})}async clearCredits(){return await this.request({request:"ClearCredits"})}async getInfo(){return await this.request({request:"GetInfo"})}async getActiveViewers(){return await this.request({request:"GetActiveViewers"})}async executeCodeTrigger(e,t,r){return r?.customEventResponse?this.executeCodeTriggerWithCustomEventResponse(e,t):await this.request({request:"ExecuteCodeTrigger",triggerName:e,args:t})}async executeCodeTriggerWithCustomEventResponse(e,t={},r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");let{responseId:o,promise:s,controller:i}=v({timeout:r,addEventListener:(c,d)=>this.on(c,d),removeEventListener:c=>{this.listeners=this.listeners.filter(d=>!c(d))}}),a={...t,sbClientResponse:o};try{let c=await this.executeCodeTrigger(e,a),d=await s;return{...c,customEventResponseArgs:d}}catch(c){throw i.signal.aborted||i.abort(),c}}async getCodeTriggers(){return await this.request({request:"GetCodeTriggers"})}async getCommands(){return await this.request({request:"GetCommands"})}async getEmotes(e){switch(e){case"twitch":return await this.request({request:"TwitchGetEmotes"});case"youtube":return await this.request({request:"YouTubeGetEmotes"});default:throw new Error("Invalid platform")}}async getGlobals(e=!0){return await this.request({request:"GetGlobals",persisted:e})}async getGlobal(e,t=!0){let r=await this.request({request:"GetGlobal",variable:e,persisted:t});return r.status==="ok"?r.variables[e]?{id:r.id,status:r.status,variable:r.variables[e]}:{status:"error",error:"Variable not found"}:r}async getUserGlobals(e,t=null,r=!0){let s={twitch:"TwitchGetUserGlobals",youtube:"YouTubeGetUserGlobals",trovo:"TrovoGetUserGlobals",kick:"KickGetUserGlobals"}[e];if(!s)throw new Error("Invalid platform");return await this.request({request:s,variable:t,persisted:r})}async getUserGlobal(e,t,r=null,o=!0){let i={twitch:"TwitchGetUserGlobal",youtube:"YouTubeGetUserGlobal",trovo:"TrovoGetUserGlobal",kick:"KickGetUserGlobal"}[e];if(!i)throw new Error("Invalid platform");let a=await this.request({request:i,userId:t,variable:r||null,persisted:o});if(a.status==="ok"&&t&&r){let c=a.variables.find(d=>d.name===r);return c?{id:a.id,status:a.status,variable:c}:{status:"error",error:"Variable not found"}}return a}async sendMessage(e,t,{bot:r=!1,internal:o=!0,...s}={}){if(!this._authenticated)return{status:"error",error:"Authentication required"};let i={platform:e,message:t,bot:r,internal:o};return["twitch","kick"].includes(e)&&s.replyId&&Object.assign(i,{replyId:s.replyId}),["youtube"].includes(e)&&s.broadcastId&&Object.assign(i,{broadcastId:s.broadcastId}),await this.request({...i,request:"SendMessage"})}async getUserPronouns(e,t){return await this.request({request:"GetUserPronouns",platform:e,userLogin:t})}};Object.assign(globalThis,{StreamerbotClient:l});return B(_);})(); diff --git a/widgets/streamer-only/scripts/emotes.js b/widgets/streamer-only/scripts/emotes.js deleted file mode 100644 index c6eafb9..0000000 --- a/widgets/streamer-only/scripts/emotes.js +++ /dev/null @@ -1,273 +0,0 @@ -"use strict"; - -class EmoteManager { - #emotes = new Map(); - #channelName = ""; - #channelId = ""; - #providers = ["7tv", "bttv", "ffz"]; - #size = "1x"; - #loaded = false; - #cacheTTL = 24 * 60 * 60 * 1000; - #CACHE_KEY = "emote-cache-v1"; - #pattern = null; - #patternSize = 0; - - constructor(config = {}) { - this.#channelName = config.channelName; - this.#channelId = config.channelId; - if (config.providers) this.#providers = config.providers; - if (config.size) this.#size = config.size; - } - - get loaded() { - return this.#loaded; - } - - get emoteCount() { - return this.#emotes.size; - } - - get providers() { - return [...this.#providers]; - } - - getEmote(name) { - return this.#emotes.get(name) || null; - } - - #buildPattern() { - if (this.#emotes.size === 0) { - this.#pattern = null; - this.#patternSize = 0; - return; - } - - if (this.#pattern && this.#emotes.size === this.#patternSize) return; - - const sorted = [...this.#emotes.keys()].sort( - (a, b) => b.length - a.length, - ); - const escaped = sorted.map((n) => - n.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), - ); - this.#pattern = new RegExp( - `(? { - const emote = this.#emotes.get(match); - if (!emote) return match; - console.log(emote); - return `${match}`; - }); - } - - async init() { - const cached = this.#loadCache(); - if (cached) { - this.#emotes = new Map(Object.entries(cached.emotes)); - this.#loaded = true; - this.#patternSize = 0; - return; - } - - await this.#fetchAll(); - this.#loaded = true; - this.#patternSize = 0; - this.#saveCache(); - } - - async forceRefresh() { - this.#emotes.clear(); - this.#patternSize = 0; - await this.#fetchAll(); - this.#loaded = true; - this.#patternSize = 0; - this.#saveCache(); - } - - async #fetchAll() { - const fetchers = []; - if (this.#providers.includes("7tv")) fetchers.push(this.#fetch7TV()); - if (this.#providers.includes("bttv")) fetchers.push(this.#fetchBTTV()); - if (this.#providers.includes("ffz")) fetchers.push(this.#fetchFFZ()); - await Promise.allSettled(fetchers); - } - - async #fetch7TV() { - try { - const globalResp = await fetch( - "https://7tv.io/v3/emote-sets/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (globalData.emotes) { - for (const emote of globalData.emotes) { - this.#add7TVEmote(emote); - } - } - - if (this.#channelId) { - const userResp = await fetch( - `https://7tv.io/v3/users/twitch/${this.#channelId}`, - ); - if (!userResp.ok) return; - const userData = await userResp.json(); - if (userData.emote_set?.emotes) { - for (const emote of userData.emote_set.emotes) { - this.#add7TVEmote(emote); - } - } - } - } catch (e) { - console.warn("7TV emote fetch failed:", e.message); - } - } - - #add7TVEmote(emote) { - const entry = emote.data || emote; - const id = entry.id || emote.id; - const name = entry.name || emote.name; - if (!id || !name) return; - const nameLower = name; - const host = entry.host.url; - this.#emotes.set(nameLower, { - url: `https:${host}/${this.#size}.webp`, - provider: "7tv", - animated: entry.animated || false, - }); - } - - async #fetchBTTV() { - try { - const globalResp = await fetch( - "https://api.betterttv.net/3/cached/emotes/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (Array.isArray(globalData)) { - for (const emote of globalData) { - this.#emotes.set(emote.code, { - url: `https://cdn.betterttv.net/emote/${emote.id}/${this.#size}`, - provider: "bttv", - animated: emote.imageType === "gif", - }); - } - } - - if (this.#channelId) { - const userResp = await fetch( - `https://api.betterttv.net/3/cached/users/twitch/${this.#channelId}`, - ); - if (!userResp.ok) return; - const userData = await userResp.json(); - const allEmotes = [ - ...(userData.channelEmotes || []), - ...(userData.sharedEmotes || []), - ]; - for (const emote of allEmotes) { - this.#emotes.set(emote.code, { - url: `https://cdn.betterttv.net/emote/${emote.id}/${this.#size}`, - provider: "bttv", - animated: emote.imageType === "gif", - }); - } - } - } catch (e) { - console.warn("BTTV emote fetch failed:", e.message); - } - } - - async #fetchFFZ() { - try { - const globalResp = await fetch( - "https://api.frankerfacez.com/v1/set/global", - ); - if (!globalResp.ok) return; - const globalData = await globalResp.json(); - if (globalData.sets) { - for (const setId in globalData.sets) { - const set = globalData.sets[setId]; - for (const emote of set.emoticons || []) { - if (emote.modifier) continue; - this.#emotes.set(emote.name, { - url: emote.urls[this.#toFFZSize(this.#size)], - provider: "ffz", - animated: false, - }); - } - } - } - - const ffzId = this.#channelName || this.#channelId; - if (ffzId) { - const roomUrl = this.#channelId - ? `https://api.frankerfacez.com/v1/room/id/${this.#channelId}` - : `https://api.frankerfacez.com/v1/room/${this.#channelName}`; - const roomResp = await fetch(roomUrl); - if (!roomResp.ok) return; - const roomData = await roomResp.json(); - if (roomData.sets) { - for (const setId in roomData.sets) { - const set = roomData.sets[setId]; - for (const emote of set.emoticons || []) { - if (emote.modifier) continue; - this.#emotes.set(emote.name, { - url: emote.urls[this.#toFFZSize(this.#size)], - provider: "ffz", - animated: false, - }); - } - } - } - } - } catch (e) { - console.warn("FFZ emote fetch failed:", e.message); - } - } - - #toFFZSize(size) { - switch (size) { - case "3x": - case "4x": - return "4"; - case "2x": - return "2"; - default: - return "1"; - } - } - - #saveCache() { - try { - const cache = { - timestamp: Date.now(), - channelId: this.#channelId, - emotes: Object.fromEntries(this.#emotes), - }; - localStorage.setItem(this.#CACHE_KEY, JSON.stringify(cache)); - } catch (e) {} - } - - #loadCache() { - try { - const raw = localStorage.getItem(this.#CACHE_KEY); - if (!raw) return null; - const cache = JSON.parse(raw); - if (cache.channelId !== this.#channelId) return null; - if (Date.now() - cache.timestamp > this.#cacheTTL) return null; - return cache; - } catch (e) { - return null; - } - } -} diff --git a/widgets/streamer-only/scripts/streamerbot.js b/widgets/streamer-only/scripts/streamerbot.js deleted file mode 100644 index 54bef1f..0000000 --- a/widgets/streamer-only/scripts/streamerbot.js +++ /dev/null @@ -1,201 +0,0 @@ -// STREAMER.BOT SETTINGS - -const client = new StreamerbotClient({ - host: configs.streamerBotSettings.host, - port: configs.streamerBotSettings.port, - endpoint: configs.streamerBotSettings.endpoint, - onConnect: onConnect, - onDisconnect: onDisconnect, - onError: onError, -}); - -function getAllLocalstorage() { - const allLocalStorage = {}; - - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - allLocalStorage[key] = localStorage.getItem(key); - } - - return JSON.stringify(allLocalStorage); -} - -client.on("General.Custom", (data) => onCustom(data)); -if (configs.userColorSettings.autoUserColor) { - client.on("Twitch.ChatMessage", (data) => onChatMessage(data)); - client.on("Kick.ChatMessage", (data) => onChatMessage(data)); -} - -let taskList; -let userColors = {}; - -function parseHexColor(hex) { - if (typeof hex !== "string") return null; - const s = hex.trim(); - const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(s); - if (!m) return null; - let h = m[1].toLowerCase(); - if (h.length === 3) { - h = h - .split("") - .map((c) => c + c) - .join(""); - } - const r = parseInt(h.slice(0, 2), 16); - const g = parseInt(h.slice(2, 4), 16); - const b = parseInt(h.slice(4, 6), 16); - return { r, g, b }; -} - -function relativeLuminance({ r, g, b }) { - const toLinear = (v) => { - const s = v / 255; - return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4); - }; - const R = toLinear(r); - const G = toLinear(g); - const B = toLinear(b); - return 0.2126 * R + 0.7152 * G + 0.0722 * B; -} - -async function onChatMessage(data) { - let userColor = data.data.user.color; // hex colour - - if (userColor != undefined || userColor != "undefined") { - // update localstorage - // get id: platform-userID - let userId = data.data.user.id; - let key = `twitch-${userId}`; - - localStorage.setItem(`${key}-color`, userColor); - userColors[`${key}-color`] = userColor; - } - - return; -} - -function onDisconnect() { - showConnectionError("Connection Failed: Unable to connect to Streamer.bot"); -} - -function onError(err) { - showConnectionError( - "Connection Failed: " + (err?.message || "Unknown error"), - ); -} - -function showConnectionError(message) { - // Remove existing popup if any - const existing = document.getElementById("connection-error"); - if (existing) existing.remove(); - - const popup = document.createElement("div"); - popup.id = "connection-error"; - popup.textContent = message; - Object.assign(popup.style, { - position: "fixed", - top: "20px", - left: "50%", - transform: "translateX(-50%)", - background: "#e53935", - color: "#fff", - padding: "12px 24px", - borderRadius: "8px", - fontFamily: "'Fredoka', sans-serif", - fontSize: "1.1rem", - fontWeight: "700", - zIndex: "9999", - boxShadow: "0 4px 12px rgba(0,0,0,0.4)", - textAlign: "center", - }); - document.body.appendChild(popup); - - // Auto-dismiss after 5 seconds - setTimeout(() => { - popup.animate([{ opacity: 1 }, { opacity: 0 }], { - duration: 300, - fill: "forwards", - }).onfinish = () => popup.remove(); - }, 5000); -} - -async function refresh() { - const response = await client.getGlobal("rython-task-bot", true); - console.log(response); - - if (response.status !== "ok" || !response.variable?.value) return; - - const users = JSON.parse(response.variable.value); - console.log(users); - const sections = transformToSections(users); - - taskList.load(sections); -} - -// LOAD TASK LIST -async function onConnect() { - taskList = new TaskList(".task-panel"); - - if (configs.emoteSettings.enabled) { - let broadcaster = await client.getBroadcaster(); - - console.log(broadcaster); - - let broadcasterName = - broadcaster.platforms.twitch?.broadcastUser ?? - broadcaster.platforms.youtube?.broadcastUser ?? - broadcaster.platforms.kick?.broadcastUser; - - let broadcasterId = - broadcaster.platforms.twitch?.broadcastUserId ?? - broadcaster.platforms.youtube?.broadcastUserId ?? - broadcaster.platforms.kick?.broadcastUserId; - - window.emoteManager = new EmoteManager({ - channelName: broadcasterName, - channelId: broadcasterId, - providers: configs.emoteSettings.providers, - size: configs.emoteSettings.size, - }); - - window.emoteManager.init().then(() => { - if (taskList) { - taskList.load(taskList.getData()); - } - }); - } - - refresh(); -} - -function transformToSections(users) { - return Object.entries(users).map(([userId, userData]) => ({ - id: userId, - title: userData.Username, - tasks: userData.Tasks.map((task) => ({ - text: task.Name, - done: task.Completed, - focused: task.Focused, - })), - })); -} - -// Update task list action by action -function onCustom(payload) { - const data = payload.data; - if (!data.source && data.source != "rython-task-bot") { - return; - } - if (!taskList) return; - const body = data.body; - const id = data.id; - const username = data.username; - - switch (body.mode) { - case "refresh": - refresh(); - break; - default: - break; - } -} diff --git a/widgets/vertical/README.md b/widgets/vertical/README.md index aec396b..52ab2a8 100644 --- a/widgets/vertical/README.md +++ b/widgets/vertical/README.md @@ -6,7 +6,7 @@ Optional widget for [Rython Task Bot v2](https://github.com/liyunze-coding/rytho Websocket server running is required for browser source to work. -> ![websocket](./images/websocket.png) +> ![websocket](../shared/images/websocket.png) 1. Streamer.Bot -> Servers/Clients -> Websocket Server 2. Auto Start: `ON`; Click on `Start Server` diff --git a/widgets/vertical/images/websocket.png b/widgets/vertical/images/websocket.png deleted file mode 100644 index 9bfc514bc14b50bdb24b91660a423d65c8db4fab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82494 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 Kb3gg=n|}j^T*xi} diff --git a/widgets/vertical/index.html b/widgets/vertical/index.html index 6fc7ee0..318dfcf 100644 --- a/widgets/vertical/index.html +++ b/widgets/vertical/index.html @@ -3,11 +3,11 @@ - + - - - + + + diff --git a/widgets/vertical/lib/streamerbot-client.js b/widgets/vertical/lib/streamerbot-client.js deleted file mode 100644 index 1f1ad44..0000000 --- a/widgets/vertical/lib/streamerbot-client.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";var Streamerbot=(()=>{var W=Object.create;var p=Object.defineProperty;var L=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var D=Object.getPrototypeOf,H=Object.prototype.hasOwnProperty;var O=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),q=(n,e)=>{for(var t in e)p(n,t,{get:e[t],enumerable:!0})},E=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of U(e))!H.call(n,o)&&o!==t&&p(n,o,{get:()=>e[o],enumerable:!(r=L(e,o))||r.enumerable});return n};var M=(n,e,t)=>(t=n!=null?W(D(n)):{},E(e||!n||!n.__esModule?p(t,"default",{value:n,enumerable:!0}):t,n)),B=n=>E(p({},"__esModule",{value:!0}),n);var G=O((Q,P)=>{"use strict";P.exports=function(){throw new Error("ws does not work in the browser. Browser clients must use the native WebSocket object")}});var _={};q(_,{Client:()=>l});var m=class{constructor(e={}){this.logLevels={verbose:0,debug:1,info:2,warn:3,error:4,none:5};this.level=e.level||"info",this.customLogger=e.customLogger}setLevel(e){this.level=e}setCustomLogger(e){this.customLogger=e}verbose(...e){this.log("verbose",...e)}debug(...e){this.log("debug",...e)}info(...e){this.log("info",...e)}warn(...e){this.log("warn",...e)}error(...e){this.log("error",...e)}log(e,...t){if(!(this.logLevels[e]y.getRandomValues(n);function C(n="req"){return`sb:client:${n}:${Date.now()}-${R(new Uint32Array(12))[0]}`}function k(n){let e;return n.code==1e3?e="Connection closed.":n.code==1001?e='Endpoint is "going away".':n.code==1002?e="Connection closed due to a protocol error.":n.code==1003||n.code==1007||n.code==1008||n.code==1010?e="Bad request.":n.code==1004?e="Reserved":n.code==1005?e="Missing status code.":n.code==1006?e="The connection was closed abnormally.":n.code==1009?e="Message size limit exceeded.":n.code==1011?e="Server terminated connection because due to unexpected condition.":n.code==1015?e="TLS handshake failure":e="Unknown error",e}async function h(n,e){let{timeout:t,message:r="Operation timed out.",controller:o}=e,s;return await Promise.race([new Promise((i,a)=>{s=setTimeout(()=>(o.abort(),console.debug("[withTimeout] timeout reached",e),a(new Error(r))),t),e.signal?.addEventListener("abort",()=>{clearTimeout(s),o?.abort(),a(new Error("Operation aborted."))},{once:!0})}),n]).finally(()=>{clearTimeout(s),o.abort()})}async function S(n){let e=new TextEncoder().encode(n),t=await T.digest("SHA-256",e),o=Array.from(new Uint8Array(t)).map(s=>s.toString(16).padStart(2,"0")).join("");return I(o)}function I(n){let e=new Uint8Array(n.match(/.{1,2}/g).map(r=>parseInt(r,16)));return btoa(String.fromCharCode.apply(null,Array.from(e)))}function v({timeout:n=1e4,addEventListener:e,removeEventListener:t}){let r=C("res"),o=new AbortController,s=o.signal,i=new Promise((a,c)=>{let d=b=>{let f=b?.data;f?.eventName===r&&(o.abort(),a(f?.args))};e("Custom.Event",d);let u=setTimeout(()=>{o.abort(),c(new Error("Timed out waiting for Custom Event"))},n);s.addEventListener("abort",()=>{clearTimeout(u),t(b=>b.events?.includes("Custom.Event")&&b.callback===d)},{once:!0})});return{responseId:r,promise:i,controller:o}}var A={scheme:"ws",host:"127.0.0.1",port:8080,endpoint:"/",immediate:!0,autoReconnect:!0,retries:-1,subscribe:{},logger:w,logLevel:"info"},l=class{constructor(e=A){this._authEnabled=!1;this._authenticated=!1;this.listeners=[];this.subscriptions={};this._explicitlyClosed=!1;this._retried=0;this._connectController=new AbortController;this._reconnectTimeout=void 0;this.options={...A,...e},this.logger=this.options.logger||null,this.logger&&this.options.logLevel&&this.logger.setLevel(this.options.logLevel),this.options.immediate===!0&&this.connect().catch(t=>this.logger?.warn("Failed to connect:",t))}get authenticated(){return!!this.socket&&this.socket.readyState===this.socket.OPEN&&this._authenticated}get ready(){return!this.socket||this.socket.readyState!==this.socket.OPEN||this._authEnabled&&!this._authenticated?!1:!!this.info&&!!this.version}async connect(e=1e4){if(this.socket?.readyState!==this.socket?.CLOSED)try{await this.disconnect()}catch{}this._explicitlyClosed=!1,this._connectController.abort(),this._connectController=new AbortController;let t=new AbortController;return this._connectController.signal.addEventListener("abort",()=>{t.abort()},{once:!0}),await h(new Promise(async(r,o)=>{try{this.options.password&&(this._authEnabled=!0);let s=`${this.options.scheme}://${this.options.host}:${this.options.port}${this.options.endpoint}`;this.logger?.debug("Connecting to Streamer.bot WebSocket server at",s,this._authEnabled?"with authentication":""),this.socket=globalThis?.process?.versions?.node?new(await Promise.resolve().then(()=>M(G(),1))).WebSocket(s):new WebSocket(s),this.socket.onmessage=this.onMessage.bind(this),this.socket.onopen=this.onOpen.bind(this),this.socket.onclose=this.onClose.bind(this),this.socket.onerror=this.onError.bind(this),this.socket.addEventListener("open",()=>{if(!this.socket)return o(new Error("WebSocket not initialized"));r()},{signal:t.signal}),this.socket.addEventListener("close",()=>o(new Error("WebSocket closed")),{once:!0})}catch(s){try{await this.disconnect(),this?.options?.onError?.(s)}catch(i){this.logger?.warn("Error invoking onError handler",i)}o(s)}}),{timeout:e,message:"WebSocket connection timeout exceeded",controller:t})}async disconnect(e=1e3,t=1e3){if(this._explicitlyClosed=!0,this._connectController.abort(),this._reconnectTimeout&&clearTimeout(this._reconnectTimeout),!this.socket||this.socket.readyState===this.socket.CLOSED)return;let r=new AbortController,o=r.signal;return await h(new Promise((s,i)=>{if(this.socket?.addEventListener("close",()=>{this.logger?.debug("Disconnected from Streamer.bot WebSocket server"),s()},{signal:o}),this.socket?.readyState!==this.socket?.CLOSING)try{this.socket?.close(e)}catch(a){i(a)}}),{timeout:t,message:"Timeout exceeded while closing connection",controller:r})}async handshake(){if(!this.socket)throw new Error("WebSocket not initialized");let e=new AbortController,{signal:t}=e;this._connectController.signal.addEventListener("abort",()=>{e.abort()},{once:!0,signal:t});let r=await h(new Promise((o,s)=>{this.socket?.addEventListener("message",async i=>{if(!("data"in i)||!i.data||typeof i.data!="string"){this.logger?.debug("Unknown message received",i);return}try{let a=JSON.parse(i.data);a&&"info"in a&&o(a)}catch(a){this.logger?.warn("Invalid JSON payload received",i.data),s(a)}},{signal:t})}),{timeout:5e3,message:"Handshake timeout exceeded",controller:e});if(!r||!("info"in r))throw new Error("Handshake failed (invalid payload)");if("request"in r&&r?.request==="Hello"&&r.authentication)return await this.authenticate(r);if(r.info&&!r.authentication){this.logger?.debug("Connected to Streamer.bot WebSocket server",r.info),this.info=r.info,this.version=r.info.version;return}throw new Error("Handshake failed (unknown)")}async authenticate(e){if(!this._authEnabled||!this.options.password){if(this.logger?.debug("No password provided for authentication. Checking if auth is enforced for all requests..."),(await this.getInfo()).status==="ok"){this._authenticated=!1,this.version=e.info.version,this.info=e.info;return}throw await this.disconnect(),new Error("Authentication required")}if(!e.authentication)throw this.logger?.debug("Missing authentication payload"),await this.disconnect(),new Error("Invalid authentication payload");this.logger?.debug("Authenticating with Streamer.bot WebSocket server...");let{salt:t,challenge:r}=e?.authentication,o=await S(`${this.options.password}${t}`),s=await S(`${o}${r}`);if((await this.request({request:"Authenticate",authentication:s})).status==="ok")this._authenticated=!0,this.version=e.info.version,this.info=e.info;else throw await this.disconnect(),new Error("Authentication failed")}async onOpen(){this._retried=0,this._reconnectTimeout&&clearTimeout(this._reconnectTimeout);try{this._authEnabled||this.getInfo().catch(()=>this.logger?.debug("Failed to fetch Streamer.bot instance info")),await this.handshake(),this.version&&this.info&&(this.logger?.debug(`Connected to Streamer.bot: v${this.version} (${this.info.name})`),await this.updateSupportedEvents(),this?.options?.onConnect?.(this.info))}catch(e){return this.logger?.warn("Failed handshake with Streamer.bot",e),this.options?.onError?.(e instanceof Error?e:new Error("Failed handshake with Streamer.bot")),await this.disconnect()}try{if(this.options.subscribe==="*"||typeof this.options.subscribe=="object"&&!Array.isArray(this.options.subscribe)&&Object.keys(this.options.subscribe??{}).length)this.logger?.debug("Subscribing to initial events from options:",this.options.subscribe),await this.subscribe(this.options.subscribe);else if(typeof this.options.subscribe=="string"||Array.isArray(this.options.subscribe)){this.logger?.debug("Subscribing to initial events from options:",this.options.subscribe);let e=await this.getSubscriptionsFromEventStrings(this.options.subscribe);this.logger?.debug("Parsed subscriptions from options:",e),e&&await this.subscribe(e)}if(this.listeners.length){let e=await this.getSubscriptionsFromListeners();await this.subscribe(e)}this.logger?.verbose("Subscribed to requested events",this.subscriptions,this.listeners)}catch(e){this.logger?.warn("Error subscribing to requested events",e)}}onClose(e){this._connectController.abort();try{(e.type==="error"||!e.wasClean)&&this.options.onError&&this?.options?.onError(new Error(k(e))),this?.options?.onDisconnect?.()}catch(t){this.logger?.warn("Error invoking user-provided onDisconnect handler",t)}if(this._explicitlyClosed||!this.options.autoReconnect)return this.logger?.debug("Cleaning up..."),this.cleanup();this._retried+=1,typeof this.options.retries=="number"&&(this.options.retries<0||this._retried{if(!(this.socket&&this.socket.readyState!==this.socket.CLOSED)){this.logger?.debug(`Reconnecting... (attempt ${this._retried})`);try{await this.connect(1e4)}catch(t){this._retried&&this.logger?.warn(`Failed to reconnect (attempt ${this._retried-1})`,t)}}},Math.min(3e4,this._retried*1e3))):(this.logger?.debug("Auto-reconnect limit reached. Cleaning up..."),this.cleanup())}async onMessage(e){if(!e.data||typeof e.data!="string"){this.logger?.debug("Unknown message received",e);return}let t;try{t=JSON.parse(e.data)}catch(r){this.logger?.warn("Invalid JSON payload received",e.data,r);return}this.logger?.verbose("RECV",t);try{this.options.onData&&this?.options?.onData(t)}catch(r){this.logger?.warn("Error occurred within user-provided onData callback",r)}if(t?.event?.source&&t?.event?.type){for(let r of this.listeners)if(r.events?.length&&r.events.find(o=>o==="*"||o===`${t?.event?.source}.${t?.event?.type}`||o.split(".",2)?.[1]==="*"&&o.split(".",2)?.[0]===t?.event?.source))try{r.callback(t)}catch(o){this.logger?.warn(`Error occurred within user-provided event callback (${r.events})`,o)}}}onError(e){this.logger?.debug("WebSocket onError",e),this.socket&&this.socket.readyState!==this.socket.OPEN&&this._connectController.abort();try{this?.options?.onError?.(new Error("WebSocket Error"))}catch(t){this.logger?.warn("Error occurred within user-provided onError callback",t)}}cleanup(){this.socket&&(this.socket.onopen=null,this.socket.onclose=null,this.socket.onerror=null,this.socket.onmessage=null,this.socket=void 0),this.listeners=[],this._retried=0,this._connectController.abort(),this._reconnectTimeout&&clearTimeout(this._reconnectTimeout)}send(e){this.socket?.send(JSON.stringify(e))}async request(e,t="",r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");t||(t=C());let o=new AbortController,s=o.signal;this._connectController.signal.addEventListener("abort",()=>{o.abort()},{once:!0,signal:s});let i=await h(new Promise((a,c)=>{this.socket?.addEventListener("message",d=>{if(!("data"in d)||!d.data||typeof d.data!="string"){this.logger?.debug("Unknown message received",d.data);return}try{let u=JSON.parse(d?.data);if(u?.id===t)return this.logger?.verbose(`RECV :: ${e.request}`,u),a(u)}catch(u){this.logger?.warn("Invalid JSON payload received",d.data),c(u)}},{signal:s}),this.logger?.verbose(`SEND :: ${e.request}`,{...e,id:t}),this.send({...e,id:t})}),{timeout:r,message:"Request timed out",controller:o,signal:s});if(i?.status==="ok"){try{this.options.onData&&this?.options?.onData(i)}catch(a){this.logger?.warn("Error invoking onData handler",a)}return{event:{source:"Request",type:e.request??"Unknown"},...i}}throw new Error("Request failed")}async on(e,t){try{if(!e)return;let r={events:[e],callback:t};if(this.listeners.push(r),this.ready){let o=await this.getSubscriptionsFromListeners([r]);await this.subscribe(o)}this.logger?.debug(`Added event listener for "${e}"`)}catch(r){this.logger?.warn(`Failed adding event listener for "${e}"`,r)}}async updateSupportedEvents(){if(this.ready)try{let e=await this.getEvents();if(e.status!=="ok"||!e.events)throw new Error(e.status);this.supportedEvents=e.events,this.logger?.debug(`Successfully fetched supported event types for Streamer.bot v${this.version}`)}catch(e){this.logger?.warn("Failed to fetch supported events from Streamer.bot, falling back to stored events type.",e),this.supportedEvents=g}}async getSupportedEvents(){return this.supportedEvents||(this.logger?.warn("Supported event types not yet initialized, fetching from Streamer.bot instance..."),await this.updateSupportedEvents()),this.supportedEvents??g}getEventsFromListeners(e){return(e??this.listeners).reduce((t,r)=>(r.events.forEach(o=>{t[o]||(t[o]=[]),t[o].push(r.callback)}),t),{})}async getSubscriptionsFromListeners(e){let t=this.getEventsFromListeners(e);return this.getSubscriptionsFromEventStrings(Object.keys(t))}async getSubscriptionsFromEventStrings(e){let t={};typeof e=="string"&&(e=[e]);for(let r of e){let o=await this.parseEventString(r);if(o)for(let s of o){let{source:i,eventTypes:a}=s,c=new Set([...t[i]??[],...a]);t[i]=[...c]}}return t}async parseEventString(e){let t=await this.getSupportedEvents();if(!e||typeof e!="string"){this.logger?.warn(`Invalid event subscription requested "${e}"`);return}if(e==="*")return Object.keys(t).map(r=>{let o=r,s=t[o]??[];return{source:o,eventTypes:s}});{let[r,o]=e.split(".",2);if(!r||!o||!(r in t)){this.logger?.warn(`Invalid event subscription requested "${e}"`);return}let s=r,i=o;if(i)return[{source:s,eventTypes:i==="*"?t[s]:[i]}];this.logger?.warn(`Invalid event type requested "${e}"`);return}}async subscribe(e){let t=await this.getSupportedEvents();e==="*"&&(e=t);for(let r in e){if(!r||r==="err")continue;if(!(r in t)){this.logger?.warn(`Attempted to subscribe to empty or unknown event source: "${r}"`,Object.keys(e));continue}let o=r,s=e[o]??[];if(s&&s.length){let i=new Set([...this.subscriptions[o]??[],...s]);this.subscriptions[o]=[...i]}}return Object.keys(this.subscriptions).length===0?(this.logger?.warn("No valid events to subscribe to. Please provide valid event sources and types."),{id:"invalid",status:"error",error:"No valid events to subscribe to"}):await this.request({request:"Subscribe",events:this.subscriptions})}async unsubscribe(e){let t=await this.getSupportedEvents();e==="*"&&(e=t);for(let r in e){if(r===void 0||!Object.keys(t).includes(r))continue;let o=r,s=e[o];if(s&&s.length)for(let i of s)i&&this.subscriptions[o]?.filter&&(this.subscriptions[o]=this.subscriptions[o])?.filter(a=>i!==a)}return await this.request({request:"UnSubscribe",events:e})}async getEvents(){return await this.request({request:"GetEvents"})}async getActions(){return await this.request({request:"GetActions"})}async doAction(e,t,r){if(r?.customEventResponse)return this.doActionWithCustomEventResponse(e,t);let o,s;return typeof e=="string"?o=e:(o=e.id,s=e.name),await this.request({request:"DoAction",action:{id:o,name:s},args:t})}async doActionWithCustomEventResponse(e,t={},r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");let{responseId:o,promise:s,controller:i}=v({timeout:r,addEventListener:(c,d)=>this.on(c,d),removeEventListener:c=>{this.listeners=this.listeners.filter(d=>!c(d))}}),a={...t,sbClientResponse:o};try{let c=await this.doAction(e,a),d=await s;return{...c,customEventResponseArgs:d}}catch(c){throw i.signal.aborted||i.abort(),c}}async getBroadcaster(){return await this.request({request:"GetBroadcaster"})}async getMonitoredYouTubeBroadcasts(){return await this.request({request:"GetMonitoredYouTubeBroadcasts"})}async getCredits(){return await this.request({request:"GetCredits"})}async testCredits(){return await this.request({request:"TestCredits"})}async clearCredits(){return await this.request({request:"ClearCredits"})}async getInfo(){return await this.request({request:"GetInfo"})}async getActiveViewers(){return await this.request({request:"GetActiveViewers"})}async executeCodeTrigger(e,t,r){return r?.customEventResponse?this.executeCodeTriggerWithCustomEventResponse(e,t):await this.request({request:"ExecuteCodeTrigger",triggerName:e,args:t})}async executeCodeTriggerWithCustomEventResponse(e,t={},r=1e4){if(!this.socket||this.socket.readyState!==this.socket.OPEN)throw new Error("WebSocket is not connected");let{responseId:o,promise:s,controller:i}=v({timeout:r,addEventListener:(c,d)=>this.on(c,d),removeEventListener:c=>{this.listeners=this.listeners.filter(d=>!c(d))}}),a={...t,sbClientResponse:o};try{let c=await this.executeCodeTrigger(e,a),d=await s;return{...c,customEventResponseArgs:d}}catch(c){throw i.signal.aborted||i.abort(),c}}async getCodeTriggers(){return await this.request({request:"GetCodeTriggers"})}async getCommands(){return await this.request({request:"GetCommands"})}async getEmotes(e){switch(e){case"twitch":return await this.request({request:"TwitchGetEmotes"});case"youtube":return await this.request({request:"YouTubeGetEmotes"});default:throw new Error("Invalid platform")}}async getGlobals(e=!0){return await this.request({request:"GetGlobals",persisted:e})}async getGlobal(e,t=!0){let r=await this.request({request:"GetGlobal",variable:e,persisted:t});return r.status==="ok"?r.variables[e]?{id:r.id,status:r.status,variable:r.variables[e]}:{status:"error",error:"Variable not found"}:r}async getUserGlobals(e,t=null,r=!0){let s={twitch:"TwitchGetUserGlobals",youtube:"YouTubeGetUserGlobals",trovo:"TrovoGetUserGlobals",kick:"KickGetUserGlobals"}[e];if(!s)throw new Error("Invalid platform");return await this.request({request:s,variable:t,persisted:r})}async getUserGlobal(e,t,r=null,o=!0){let i={twitch:"TwitchGetUserGlobal",youtube:"YouTubeGetUserGlobal",trovo:"TrovoGetUserGlobal",kick:"KickGetUserGlobal"}[e];if(!i)throw new Error("Invalid platform");let a=await this.request({request:i,userId:t,variable:r||null,persisted:o});if(a.status==="ok"&&t&&r){let c=a.variables.find(d=>d.name===r);return c?{id:a.id,status:a.status,variable:c}:{status:"error",error:"Variable not found"}}return a}async sendMessage(e,t,{bot:r=!1,internal:o=!0,...s}={}){if(!this._authenticated)return{status:"error",error:"Authentication required"};let i={platform:e,message:t,bot:r,internal:o};return["twitch","kick"].includes(e)&&s.replyId&&Object.assign(i,{replyId:s.replyId}),["youtube"].includes(e)&&s.broadcastId&&Object.assign(i,{broadcastId:s.broadcastId}),await this.request({...i,request:"SendMessage"})}async getUserPronouns(e,t){return await this.request({request:"GetUserPronouns",platform:e,userLogin:t})}};Object.assign(globalThis,{StreamerbotClient:l});return B(_);})();