const { getStreamFromURL } = global.utils; module.exports = { config: { name: "theme", aliases: ["aitheme"], version: "5.0", author: "xalman", countDown: 5, role: 1, description: "Create and apply AI themes for group chats", category: "box chat", guide: "{pn} - Show current theme\n{pn} id - Show theme ID\n{pn} apply - Apply theme\n{pn} - Generate AI themes" }, onReply: async function ({ message, Reply, event, api }) { const { author, themes, threadID, messageID } = Reply; const currentUserId = event.senderID || event.userID || (event.from && event.from.id); if (currentUserId !== author) { return message.reply('āŒ Only the person who generated these themes can select one.'); } const selection = parseInt((event.body || event.text || '').trim()); if (!selection || selection < 1 || selection > themes.length) { return message.reply(`āŒ Invalid selection. Please reply with a number between 1 and ${themes.length}.`); } const selectedTheme = themes[selection - 1]; try { if (messageID && typeof api.unsendMessage === "function") { try { await api.unsendMessage(messageID); } catch (e) {} } const themeId = selectedTheme.id || selectedTheme.themeId || selectedTheme.theme_fbid; if (!themeId) { return message.reply('āŒ Selected theme does not have a valid theme ID.'); } await new Promise((resolve, reject) => { api.changeThreadColor(themeId, threadID, (err, result) => { if (err) reject(err); else resolve(result); }); }); const themeName = selectedTheme.accessibility_label || selectedTheme.name || "AI Theme"; let successMsg = `āœ… Theme applied successfully!\nšŸ“ Name: ${themeName}\nšŸ†” ID: ${themeId}`; const attachments = []; const imageUrl = selectedTheme.background_asset?.image?.url || selectedTheme.backgroundImage || selectedTheme.image || selectedTheme.images?.background; if (imageUrl) { try { const stream = await getStreamFromURL(imageUrl); if (stream) attachments.push(stream); } catch (imgErr) { console.log('Failed to load theme image:', imgErr); } } return message.reply({ body: successMsg, attachment: attachments.length > 0 ? attachments : undefined }); } catch (error) { console.error('Theme apply error:', error); return message.reply(`āŒ Failed to apply theme: ${error.message || error}`); } }, onStart: async function ({ args, message, event, api, commandName }) { const { threadID, senderID } = event; const command = String(args[0] || "").toLowerCase().trim(); if (command === "id") { try { const threadInfo = await api.getThreadInfo(threadID); const theme = threadInfo?.threadTheme || {}; const themeId = theme.id || theme.theme_fbid || theme.themeId || threadInfo?.color || "Unknown"; const color = theme.accessibility_label || theme.name || threadInfo?.color || "Unknown"; return message.reply( `╭──〔 THEME ID 〕──╮\n│\n│ šŸ“Œ ID: ${themeId}\n│ šŸŽØ Color: ${color}\n│\n╰─────────────────` ); } catch (error) { return message.reply(`āŒ Failed to get current theme.\n\n${error.message || error}`); } } if (command === "apply" || command === "set") { const themeId = args.slice(1).join(" ").trim(); if (!themeId) { return message.reply("āŒ Please provide a theme ID.\n\nExample: /theme apply 739785333579430"); } try { await new Promise((resolve, reject) => { api.changeThreadColor(themeId, threadID, (err, result) => { if (err) reject(err); else resolve(result); }); }); return message.reply(`āœ… Theme applied successfully!\nšŸ“Œ ID: ${themeId}`); } catch (error) { return message.reply(`āŒ Failed to apply theme: ${error.message || error}`); } } const prompt = args.join(" ").trim(); if (!prompt) { try { const threadInfo = await api.getThreadInfo(threadID); const theme = threadInfo?.threadTheme; if (!theme) { return message.reply( `╭──〔 CURRENT THEME 〕──╮\n│\n│ ā„¹ļø Default theme\n│\n│ šŸ’” Use: /theme \n│ to generate AI themes\n╰────────────────────` ); } const themeId = theme.id || theme.theme_fbid || theme.themeId || threadInfo?.color || "Unknown"; const color = theme.accessibility_label || theme.name || threadInfo?.color || "Unknown"; return message.reply( `╭──〔 CURRENT THEME 〕──╮\n│\n│ šŸ“Œ ID: ${themeId}\n│ šŸŽØ Color: ${color}\n│\n│ šŸ’” Change: /theme apply \n│ šŸ’” Generate: /theme \n╰────────────────────` ); } catch (error) { return message.reply(`āŒ Failed to get current theme.\n\n${error.message || error}`); } } if (typeof api.createThemeAI !== "function" && typeof api.metaTheme !== "function") { return message.reply( "āŒ Your current FCA does not support AI theme generation.\n\nPlease update your FCA/package to a version that provides `api.createThemeAI()` or `api.metaTheme()`." ); } try { await message.reply(`šŸŽØ Generating AI themes...\n\nšŸ“ ${prompt}`); let themes = []; if (typeof api.createThemeAI === "function") { const promises = []; for (let i = 0; i < 5; i++) { promises.push(new Promise((resolve, reject) => { api.createThemeAI(prompt, (err, data) => { if (err) reject(err); else resolve(data); }); })); } const results = await Promise.allSettled(promises); themes = results .filter(r => r.status === "fulfilled") .map(r => r.value) .filter(theme => theme && (theme.id || theme.themeId || theme.theme_fbid)); if (themes.length === 0) { return message.reply("āŒ No themes were generated.\n\nTry a different description."); } } else { const result = await new Promise((resolve, reject) => { api.metaTheme(prompt, { numThemes: 5 }, (err, data) => { if (err) reject(err); else resolve(data); }); }); themes = normalizeThemes(result); } if (!themes || themes.length === 0) { return message.reply("āŒ No themes were generated.\n\nTry a different description."); } let themeList = ""; const attachments = []; for (let i = 0; i < themes.length; i++) { const theme = themes[i]; const themeId = theme.id || theme.themeId || theme.theme_fbid || "Unknown"; const themeName = theme.accessibility_label || theme.name || theme.label || "AI Generated"; themeList += `${i + 1}. šŸ“ Name: ${themeName}\n`; themeList += ` šŸ†” ID: ${themeId}\n\n`; const imageUrl = theme.background_asset?.image?.url || theme.backgroundImage || theme.image || theme.images?.background; if (imageUrl) { try { const stream = await getStreamFromURL(imageUrl); if (stream) attachments.push(stream); } catch (err) { console.error(`Preview ${i + 1} failed:`, err.message); } } } const replyMessage = `╭──〔 AI THEME GENERATOR 〕──╮\n│\n│ ✨ Generated ${themes.length} theme(s)!\n│ šŸ“ ${prompt}\n│\n${themeList}│ šŸ’¬ Reply with a number (1-${themes.length})\n│ to apply the theme.\n╰──────────────────────────`; const replyData = { body: replyMessage }; if (attachments.length > 0) replyData.attachment = attachments; return message.reply(replyData, (err, info) => { if (err || !info?.messageID) return; if (!global.GoatBot?.onReply?.set) return; global.GoatBot.onReply.set(info.messageID, { commandName, messageID: info.messageID, author: senderID, threadID, themes: themes, createdAt: Date.now() }); }); } catch (error) { console.error("[THEME] Generation Error:", error); return message.reply(`āŒ Theme generation failed.\n\nReason: ${error.message || error}`); } } }; function normalizeThemes(result) { if (!result) return []; if (Array.isArray(result)) return result; if (result.themes && Array.isArray(result.themes)) return result.themes; if (result.data?.themes && Array.isArray(result.data.themes)) return result.data.themes; if (result.results && Array.isArray(result.results)) return result.results; if (result.data && Array.isArray(result.data)) return result.data; if (result.id || result.themeId || result.theme_fbid) return [result]; return []; }