feat(channels): add Twitch config compatibility

This commit is contained in:
晴天
2026-05-23 08:42:54 +08:00
parent 8623efd49c
commit dcc3751ded
7 changed files with 366 additions and 10 deletions

View File

@@ -21,6 +21,7 @@ export const CHANNEL_LABELS = {
mattermost: 'Mattermost',
clickclack: 'ClickClack',
'nextcloud-talk': 'Nextcloud Talk',
twitch: 'Twitch',
'openclaw-weixin': '微信',
weixin: '微信',
}

View File

@@ -161,6 +161,23 @@ export default {
nextcloudTalkGroupAllowFromHint: _('可选,逗号分隔允许的 room token。', 'Optional comma-separated room tokens.'),
nextcloudTalkPrivateNetworkHint: _('仅在 Nextcloud 部署于可信内网且 Gateway 可以访问时开启。', 'Enable only when Nextcloud runs on a trusted private network reachable by Gateway.'),
nextcloudTalkSecretOrFile: _('Bot Secret 或 Secret File', 'Bot Secret or Secret File'),
twitchDesc: _('接入 Twitch 聊天频道,支持直播间消息、角色过滤和 OAuth Token 配置', 'Connect Twitch chat with channel messages, role filters, and OAuth token settings'),
twitchGuide1: _('在 Twitch 开发者控制台创建应用,获取 <strong>Client ID</strong>', 'Create an app in the Twitch developer console and copy the <strong>Client ID</strong>'),
twitchGuide2: _('为机器人账号准备 OAuth Access Token至少包含 <code>chat:read</code> 和 <code>chat:write</code> 权限', 'Prepare an OAuth access token for the bot account with at least <code>chat:read</code> and <code>chat:write</code> scopes'),
twitchGuide3: _('填写机器人 Username 和要监听的 ChannelChannel 可不带 #', 'Fill the bot username and target channel; the channel can be entered without #'),
twitchGuide4: _('保存后面板会安装 Twitch 插件并重载 Gateway实际连通性以 Gateway 日志或 channels status 为准', 'After saving, the panel installs the Twitch plugin and reloads Gateway; verify connectivity through Gateway logs or channels status'),
twitchGuideFooter: _('<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">Twitch 最小配置需要 Username、Access Token、Client ID 与 Channel。</div>', '<div style="margin-top:8px;font-size:var(--font-size-xs);color:var(--text-tertiary)">Twitch minimally requires Username, Access Token, Client ID, and Channel.</div>'),
twitchUsernameHint: _('机器人登录名,通常是不带 @ 的 Twitch 用户名。', 'Bot login name, usually the Twitch username without @.'),
twitchAccessTokenHint: _('OAuth Access Token可带 oauth: 前缀;生产环境建议使用 SecretRef。', 'OAuth access token; oauth: prefix is allowed. Prefer SecretRef in production.'),
twitchClientIdHint: _('Twitch 开发者控制台中的应用 Client ID。', 'Application Client ID from the Twitch developer console.'),
twitchChannelHint: _('目标直播间频道名,可填写 openclaw 或 #openclaw。', 'Target chat channel, e.g. openclaw or #openclaw.'),
twitchAllowFromHint: _('可选,逗号分隔允许发起对话的 Twitch 用户 ID。', 'Optional comma-separated Twitch user IDs allowed to start conversations.'),
twitchAllowedRolesHint: _('可选,逗号分隔 moderator、owner、vip、subscriber、all。', 'Optional comma-separated roles: moderator, owner, vip, subscriber, all.'),
twitchRequireMention: _('要求提及机器人', 'Require mention'),
twitchClientSecretHint: _('可选;仅在需要刷新 Token 的 OAuth 流程中填写。', 'Optional; only needed for OAuth flows that refresh tokens.'),
twitchRefreshTokenHint: _('可选;与 Client Secret 配合用于刷新 Access Token。', 'Optional; used with Client Secret to refresh the access token.'),
twitchExpiresInHint: _('Access Token 有效期,单位秒。', 'Access token lifetime in seconds.'),
twitchObtainmentTimestampHint: _('Token 获取时间戳;上游用于判断刷新时机。', 'Token obtainment timestamp; upstream uses it to decide refresh timing.'),
synologyChatDesc: _('接入群晖 Synology Chat适合 NAS 内网团队协作', 'Connect Synology Chat for NAS-hosted team messaging'),
synologyChatGuide1: _('在 Synology Chat 管理后台创建 Bot并复制 Token', 'Create a bot in Synology Chat administration and copy its Token'),
synologyChatGuide2: _('配置 Incoming Webhook 或机器人发消息 URL填入 Incoming URL', 'Configure an Incoming Webhook or bot post URL, then paste it as Incoming URL'),

View File

@@ -356,6 +356,36 @@ const PLATFORM_REGISTRY = {
pluginRequired: '@openclaw/nextcloud-talk@latest',
pluginId: 'nextcloud-talk',
},
twitch: {
label: 'Twitch',
iconName: 'message-square',
desc: t('channels.twitchDesc'),
guide: [
t('channels.twitchGuide1'),
t('channels.twitchGuide2'),
t('channels.twitchGuide3'),
t('channels.twitchGuide4'),
],
guideFooter: t('channels.twitchGuideFooter'),
fields: [
{ key: 'username', label: 'Username', placeholder: t('channels.optionalEg', { example: 'openclaw' }), required: true, hint: t('channels.twitchUsernameHint') },
{ key: 'accessToken', label: 'Access Token', placeholder: 'oauth:abc123...', secret: true, required: true, hint: t('channels.twitchAccessTokenHint') },
{ key: 'clientId', label: 'Client ID', placeholder: 'abc123clientid', required: true, hint: t('channels.twitchClientIdHint') },
{ key: 'channel', label: 'Channel', placeholder: 'openclaw', required: true, hint: t('channels.twitchChannelHint') },
{ key: 'allowFrom', label: 'Allow From', placeholder: '123456789, 987654321', required: false, hint: t('channels.twitchAllowFromHint') },
{ key: 'allowedRoles', label: 'Allowed Roles', placeholder: 'moderator, vip, subscriber', required: false, hint: t('channels.twitchAllowedRolesHint') },
{ key: 'requireMention', label: t('channels.twitchRequireMention'), type: 'select', options: BOOLEAN_OPTIONS, required: false },
{ key: 'responsePrefix', label: 'Response Prefix', placeholder: t('channels.optionalEg', { example: '[AI]' }), required: false },
{ key: 'clientSecret', label: 'Client Secret', placeholder: t('channels.optionalEg', { example: 'client-secret' }), secret: true, required: false, hint: t('channels.twitchClientSecretHint') },
{ key: 'refreshToken', label: 'Refresh Token', placeholder: t('channels.optionalEg', { example: 'refresh-token' }), secret: true, required: false, hint: t('channels.twitchRefreshTokenHint') },
{ key: 'expiresIn', label: 'Expires In', placeholder: '3600', required: false, hint: t('channels.twitchExpiresInHint') },
{ key: 'obtainmentTimestamp', label: 'Obtainment Timestamp', placeholder: '1779490000', required: false, hint: t('channels.twitchObtainmentTimestampHint') },
],
configKey: 'twitch',
pairingChannel: 'twitch',
pluginRequired: '@openclaw/twitch@latest',
pluginId: 'twitch',
},
'synology-chat': {
label: 'Synology Chat',
iconName: 'message-square',
@@ -878,7 +908,7 @@ function applyRouteIntent(page, state) {
// ── 已配置平台渲染 ──
// ── 多账号支持的平台:与 OpenClaw 的 accounts/defaultAccount 配置模型保持一致 ──
const MULTI_INSTANCE_PLATFORMS = ['telegram', 'discord', 'slack', 'feishu', 'dingtalk', 'dingtalk-connector', 'qqbot', 'zalo', 'zalouser', 'line', 'mattermost', 'clickclack', 'nextcloud-talk', 'synology-chat', 'googlechat', 'signal']
const MULTI_INSTANCE_PLATFORMS = ['telegram', 'discord', 'slack', 'feishu', 'dingtalk', 'dingtalk-connector', 'qqbot', 'zalo', 'zalouser', 'line', 'mattermost', 'clickclack', 'nextcloud-talk', 'twitch', 'synology-chat', 'googlechat', 'signal']
function supportsMessagingMultiAccount(pid) {
return MULTI_INSTANCE_PLATFORMS.includes(pid)