87 lines
4.6 KiB
JavaScript
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 };
|