Lumi/plugins/lumi_overlay/backend/sources.js
2026-07-26 22:06:34 +02:00

87 lines
4.6 KiB
JavaScript

"use strict";
const { configuredChannels } = require("../../../src/services/twitch-eventsub");
const { getClient: getYouTubeClient } = require("../../../src/services/youtube");
const { getClient: getDiscordClient } = require("../../../src/services/discord");
const { twitchEventSubManager } = require("../../../src/services/twitch-eventsub");
const { listEventTypes } = require("../../../src/services/lumi-events");
const { getPlatformLiveState } = require("../../../src/services/platform-live-state");
const { getSetting } = require("../../../src/services/settings");
function listSources() {
const sources = configuredChannels().map((channel) => ({
id: `twitch:${channel}`, platform: "twitch", label: `Twitch · ${channel}`, channel_id: channel,
live: getPlatformLiveState("twitch", channel)?.live ?? null, available: true,
status: getPlatformLiveState("twitch", channel)?.live ? "live" : "configured"
}));
const youtube = getYouTubeClient();
const youtubeChannelId = youtube?.channelId || getSetting("youtube_bot_channel_id", "");
if (youtubeChannelId) sources.push({
id: `youtube:${youtubeChannelId}`, platform: "youtube", label: `YouTube · ${youtube?.channelName || youtubeChannelId}`,
channel_id: youtubeChannelId, live: youtube ? Boolean(youtube.liveChatId) : null, available: Boolean(youtube),
status: youtube ? (youtube.liveChatId ? "live" : "offline") : "not connected"
});
const discord = getDiscordClient();
for (const guild of discord?.guilds?.cache?.values?.() || []) {
for (const channel of guild.channels?.cache?.values?.() || []) {
if (!isReadableTextChannel(channel, discord)) continue;
sources.push({
id: `discord:${guild.id}:${channel.id}`, platform: "discord",
label: `Discord · ${guild.name} / #${channel.name || channel.id}`,
channel_id: channel.id, guild_id: guild.id, live: null, available: true, status: "connected"
});
}
}
return sources.sort((left, right) => left.label.localeCompare(right.label));
}
function listStatuses() {
const youtube = getYouTubeClient();
const discord = getDiscordClient();
const twitch = twitchEventSubManager.getStatus();
const missing = Object.values(twitch.capabilities || {}).filter((value) => String(value).startsWith("missing "));
return [
{ platform: "twitch", ...twitch, detail: `${twitch.detail}${missing.length ? ` Limited events: ${missing.join(", ")}.` : ""}` },
{ platform: "youtube", state: youtube ? "connected" : "unavailable", detail: youtube ? (youtube.liveChatId ? "Receiving live chat." : "Connected; no live chat is active.") : "YouTube is not configured." },
{ platform: "discord", state: discord?.isReady?.() ? "connected" : "unavailable", detail: discord?.isReady?.() ? "Discord is connected." : "Discord is not connected." }
];
}
function sourceIdForChat(message) {
if (message.platform === "twitch") return `twitch:${normalize(message.channel?.name || message.channel?.key || message.channel?.id)}`;
if (message.platform === "youtube") {
const youtube = getYouTubeClient();
return `youtube:${youtube?.channelId || message.channel?.id || normalize(message.channel?.key || message.channel?.name)}`;
}
if (message.platform === "discord") {
const [guildId, channelId] = String(message.channel?.key || "").split("/");
return `discord:${guildId || "unknown"}:${channelId || message.channel?.id || "unknown"}`;
}
return `${normalize(message.platform)}:${normalize(message.channel?.id || message.channel?.key)}`;
}
function sourceIdForEvent(event) {
const payload = event.payload || {};
if (event.type.startsWith("twitch.")) return `twitch:${normalize(payload.broadcaster_name || payload.broadcaster_id)}`;
if (event.type.startsWith("youtube.")) return `youtube:${payload.channel_id || payload.live_chat_id || "current"}`;
if (event.type.startsWith("discord.")) return `discord:${payload.guild_id || "unknown"}:${payload.channel_id || "*"}`;
return "";
}
function isReadableTextChannel(channel, discord) {
const text = typeof channel?.isTextBased === "function" ? channel.isTextBased() : ["GUILD_TEXT", 0].includes(channel?.type);
if (!text || !channel?.guild) return false;
try {
const permissions = channel.permissionsFor?.(discord.user);
if (!permissions) return true;
for (const flag of ["ViewChannel", "VIEW_CHANNEL", 1024n]) {
try { if (permissions.has?.(flag)) return true; } catch {}
}
return false;
} catch { return false; }
}
function normalize(value) { return String(value || "").trim().toLowerCase().replace(/^#/, ""); }
module.exports = { listSources, listStatuses, sourceIdForChat, sourceIdForEvent, listEventTypes, isReadableTextChannel };