UNPKG

karin-plugin-timechange

Version:

Karin智能头像切换插件 - 根据时间自动在白天和晚上切换不同的头像

370 lines (368 loc) 17.7 kB
import { AvatarConfig } from "../chunk-G5C6VDKH.js"; // src/apps/avatar-changer.ts import { karin, logger } from "node-karin"; import path from "path"; import fs from "fs"; var avatarConfig = new AvatarConfig(); function getCurrentTimeType() { const now = /* @__PURE__ */ new Date(); const hour = now.getHours(); const config = avatarConfig.getConfig(); if (hour >= config.dayStartHour && hour < config.nightStartHour) { return "day"; } else { return "night"; } } async function changeAvatar(bot, forceType) { try { const timeType = forceType || getCurrentTimeType(); const config = avatarConfig.getConfig(); const avatarPath = timeType === "day" ? config.dayAvatarPath : config.nightAvatarPath; if (!avatarPath) { logger.warn(`[\u5934\u50CF\u5207\u6362] \u672A\u914D\u7F6E${timeType === "day" ? "\u767D\u5929" : "\u665A\u4E0A"}\u5934\u50CF\u8DEF\u5F84`); return false; } if (!fs.existsSync(avatarPath)) { logger.warn(`[\u5934\u50CF\u5207\u6362] \u5934\u50CF\u6587\u4EF6\u4E0D\u5B58\u5728: ${avatarPath}`); return false; } const avatarBuffer = fs.readFileSync(avatarPath); const base64Avatar = `base64://${avatarBuffer.toString("base64")}`; const result = await bot.setAvatar(base64Avatar); if (result) { avatarConfig.updateLastSwitch(timeType); logger.info(`[\u5934\u50CF\u5207\u6362] \u6210\u529F\u5207\u6362\u5230${timeType === "day" ? "\u767D\u5929" : "\u665A\u4E0A"}\u5934\u50CF`); return true; } else { logger.error(`[\u5934\u50CF\u5207\u6362] \u5934\u50CF\u5207\u6362\u5931\u8D25`); return false; } } catch (error) { logger.error(`[\u5934\u50CF\u5207\u6362] \u5934\u50CF\u5207\u6362\u51FA\u9519: ${error}`); return false; } } var avatarScheduleTask = karin.task("\u5934\u50CF\u81EA\u52A8\u5207\u6362", "0 0 */1 * * *", async () => { const config = avatarConfig.getConfig(); if (!config.autoSwitch) { return; } const currentTimeType = getCurrentTimeType(); if (!avatarConfig.shouldSwitch(currentTimeType)) { logger.debug(`[\u5934\u50CF\u5207\u6362] \u5F53\u524D\u5DF2\u662F${currentTimeType === "day" ? "\u767D\u5929" : "\u665A\u4E0A"}\u5934\u50CF\uFF0C\u65E0\u9700\u5207\u6362`); return; } logger.info("[\u5934\u50CF\u5207\u6362] \u5F00\u59CB\u6267\u884C\u5B9A\u65F6\u5934\u50CF\u5207\u6362\u68C0\u67E5"); const bots = karin.getBots(); for (const bot of bots) { if (bot.isOnline()) { const success = await changeAvatar(bot); if (success) { logger.info(`[\u5934\u50CF\u5207\u6362] Bot ${bot.account} \u5934\u50CF\u5207\u6362\u6210\u529F`); } else { logger.warn(`[\u5934\u50CF\u5207\u6362] Bot ${bot.account} \u5934\u50CF\u5207\u6362\u5931\u8D25`); } await new Promise((resolve) => setTimeout(resolve, 2e3)); } } }, { log: false }); var switchToDayAvatar = karin.command("^(#)?\u5207\u6362\u767D\u5929\u5934\u50CF$", async (e) => { const config = avatarConfig.getConfig(); if (!config.dayAvatarPath) { await e.reply("\u274C \u672A\u914D\u7F6E\u767D\u5929\u5934\u50CF\uFF0C\u8BF7\u5148\u4F7F\u7528 #\u8BBE\u7F6E\u767D\u5929\u5934\u50CF \u547D\u4EE4\u914D\u7F6E"); return true; } const success = await changeAvatar(e.bot, "day"); if (success) { await e.reply("\u2705 \u5DF2\u5207\u6362\u5230\u767D\u5929\u5934\u50CF \u2600\uFE0F"); } else { await e.reply("\u274C \u767D\u5929\u5934\u50CF\u5207\u6362\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5934\u50CF\u6587\u4EF6\u662F\u5426\u5B58\u5728"); } return true; }, { name: "\u5207\u6362\u767D\u5929\u5934\u50CF", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u5207\u6362\u5934\u50CF\u54E6~" }); var switchToNightAvatar = karin.command("^(#)?\u5207\u6362\u665A\u4E0A\u5934\u50CF$", async (e) => { const config = avatarConfig.getConfig(); if (!config.nightAvatarPath) { await e.reply("\u274C \u672A\u914D\u7F6E\u665A\u4E0A\u5934\u50CF\uFF0C\u8BF7\u5148\u4F7F\u7528 #\u8BBE\u7F6E\u665A\u4E0A\u5934\u50CF \u547D\u4EE4\u914D\u7F6E"); return true; } const success = await changeAvatar(e.bot, "night"); if (success) { await e.reply("\u2705 \u5DF2\u5207\u6362\u5230\u665A\u4E0A\u5934\u50CF \u{1F319}"); } else { await e.reply("\u274C \u665A\u4E0A\u5934\u50CF\u5207\u6362\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u5934\u50CF\u6587\u4EF6\u662F\u5426\u5B58\u5728"); } return true; }, { name: "\u5207\u6362\u665A\u4E0A\u5934\u50CF", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u5207\u6362\u5934\u50CF\u54E6~" }); var autoSwitchAvatar = karin.command("^(#)?\u81EA\u52A8\u5207\u6362\u5934\u50CF$", async (e) => { const timeType = getCurrentTimeType(); const success = await changeAvatar(e.bot); if (success) { const emoji = timeType === "day" ? "\u2600\uFE0F" : "\u{1F319}"; await e.reply(`\u2705 \u5DF2\u81EA\u52A8\u5207\u6362\u5230${timeType === "day" ? "\u767D\u5929" : "\u665A\u4E0A"}\u5934\u50CF ${emoji}`); } else { await e.reply("\u274C \u81EA\u52A8\u5934\u50CF\u5207\u6362\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u914D\u7F6E\u548C\u5934\u50CF\u6587\u4EF6"); } return true; }, { name: "\u81EA\u52A8\u5207\u6362\u5934\u50CF", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u5207\u6362\u5934\u50CF\u54E6~" }); var avatarStatus = karin.command("^(#)?\u5934\u50CF\u72B6\u6001$", async (e) => { const config = avatarConfig.getConfig(); const timeType = getCurrentTimeType(); const now = /* @__PURE__ */ new Date(); let statusMsg = "\u{1F4CA} \u5934\u50CF\u5207\u6362\u72B6\u6001\n"; statusMsg += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 `; statusMsg += `\u{1F550} \u5F53\u524D\u65F6\u95F4: ${now.getHours()}:${now.getMinutes().toString().padStart(2, "0")} `; statusMsg += `\u23F0 \u5F53\u524D\u65F6\u6BB5: ${timeType === "day" ? "\u767D\u5929 \u2600\uFE0F" : "\u665A\u4E0A \u{1F319}"} `; statusMsg += `\u{1F504} \u81EA\u52A8\u5207\u6362: ${config.autoSwitch ? "\u5DF2\u5F00\u542F \u2705" : "\u5DF2\u5173\u95ED \u274C"} `; statusMsg += `\u{1F305} \u767D\u5929\u65F6\u95F4: ${config.dayStartHour}:00 - ${config.nightStartHour}:00 `; statusMsg += `\u{1F303} \u665A\u4E0A\u65F6\u95F4: ${config.nightStartHour}:00 - ${config.dayStartHour}:00 `; statusMsg += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 `; statusMsg += `\u{1F4C1} \u767D\u5929\u5934\u50CF: ${config.dayAvatarPath ? "\u5DF2\u914D\u7F6E \u2705" : "\u672A\u914D\u7F6E \u274C"} `; statusMsg += `\u{1F4C1} \u665A\u4E0A\u5934\u50CF: ${config.nightAvatarPath ? "\u5DF2\u914D\u7F6E \u2705" : "\u672A\u914D\u7F6E \u274C"} `; if (config.dayAvatarPath) { statusMsg += ` \u2514 ${fs.existsSync(config.dayAvatarPath) ? "\u6587\u4EF6\u5B58\u5728 \u2705" : "\u6587\u4EF6\u4E0D\u5B58\u5728 \u274C"} `; } if (config.nightAvatarPath) { statusMsg += ` \u2514 ${fs.existsSync(config.nightAvatarPath) ? "\u6587\u4EF6\u5B58\u5728 \u2705" : "\u6587\u4EF6\u4E0D\u5B58\u5728 \u274C"} `; } await e.reply(statusMsg); return true; }, { name: "\u5934\u50CF\u72B6\u6001", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u67E5\u770B\u5934\u50CF\u72B6\u6001\u54E6~" }); var toggleAutoSwitch = karin.command("^(#)?(\u5F00\u542F|\u5173\u95ED)\u81EA\u52A8\u5207\u6362$", async (e) => { const action = e.msg.includes("\u5F00\u542F") ? "enable" : "disable"; avatarConfig.setAutoSwitch(action === "enable"); await e.reply(`\u2705 \u5DF2${action === "enable" ? "\u5F00\u542F" : "\u5173\u95ED"}\u5934\u50CF\u81EA\u52A8\u5207\u6362\u529F\u80FD`); return true; }, { name: "\u5207\u6362\u81EA\u52A8\u6A21\u5F0F", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u4FEE\u6539\u81EA\u52A8\u5207\u6362\u8BBE\u7F6E\u54E6~" }); var setTimeRange = karin.command("^(#)?\u8BBE\u7F6E\u65F6\u95F4\u6BB5\\s+(\\d{1,2})\\s+(\\d{1,2})$", async (e) => { const matches = e.msg.match(/^(#)?设置时间段\s+(\d{1,2})\s+(\d{1,2})$/); if (!matches) { await e.reply("\u274C \u683C\u5F0F\u9519\u8BEF\uFF0C\u8BF7\u4F7F\u7528\uFF1A#\u8BBE\u7F6E\u65F6\u95F4\u6BB5 \u767D\u5929\u5F00\u59CB\u5C0F\u65F6 \u665A\u4E0A\u5F00\u59CB\u5C0F\u65F6\n\u4F8B\u5982\uFF1A#\u8BBE\u7F6E\u65F6\u95F4\u6BB5 6 18"); return true; } const dayStart = parseInt(matches[2]); const nightStart = parseInt(matches[3]); if (dayStart < 0 || dayStart > 23 || nightStart < 0 || nightStart > 23) { await e.reply("\u274C \u5C0F\u65F6\u6570\u5FC5\u987B\u57280-23\u4E4B\u95F4"); return true; } if (dayStart === nightStart) { await e.reply("\u274C \u767D\u5929\u548C\u665A\u4E0A\u7684\u5F00\u59CB\u65F6\u95F4\u4E0D\u80FD\u76F8\u540C"); return true; } avatarConfig.setTimeRange(dayStart, nightStart); await e.reply(`\u2705 \u65F6\u95F4\u6BB5\u8BBE\u7F6E\u6210\u529F \u{1F305} \u767D\u5929: ${dayStart}:00 - ${nightStart}:00 \u{1F303} \u665A\u4E0A: ${nightStart}:00 - ${dayStart}:00`); return true; }, { name: "\u8BBE\u7F6E\u65F6\u95F4\u6BB5", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u8BBE\u7F6E\u65F6\u95F4\u6BB5\u54E6~" }); var avatarHelp = karin.command("^(#)?\u5934\u50CF\u5E2E\u52A9$", async (e) => { const helpMsg = `\u{1F3AD} \u5934\u50CF\u81EA\u52A8\u5207\u6362\u63D2\u4EF6\u5E2E\u52A9 \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F4CB} \u57FA\u7840\u547D\u4EE4\uFF1A \u2022 #\u5934\u50CF\u72B6\u6001 - \u67E5\u770B\u5F53\u524D\u914D\u7F6E\u72B6\u6001 \u2022 #\u5207\u6362\u767D\u5929\u5934\u50CF - \u624B\u52A8\u5207\u6362\u5230\u767D\u5929\u5934\u50CF \u2022 #\u5207\u6362\u665A\u4E0A\u5934\u50CF - \u624B\u52A8\u5207\u6362\u5230\u665A\u4E0A\u5934\u50CF \u2022 #\u81EA\u52A8\u5207\u6362\u5934\u50CF - \u6839\u636E\u5F53\u524D\u65F6\u95F4\u81EA\u52A8\u5207\u6362 \u2022 #\u5F00\u542F\u81EA\u52A8\u5207\u6362 - \u5F00\u542F\u5B9A\u65F6\u81EA\u52A8\u5207\u6362 \u2022 #\u5173\u95ED\u81EA\u52A8\u5207\u6362 - \u5173\u95ED\u5B9A\u65F6\u81EA\u52A8\u5207\u6362 \u2022 #\u8BBE\u7F6E\u65F6\u95F4\u6BB5 6 18 - \u8BBE\u7F6E\u65F6\u95F4\u6BB5 \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F4C1} \u5934\u50CF\u7BA1\u7406\u547D\u4EE4\uFF1A \u2022 #\u4E0A\u4F20\u5934\u50CF \u767D\u5929 - \u4E0A\u4F20\u767D\u5929\u5934\u50CF\uFF08\u63A8\u8350\uFF09 \u2022 #\u4E0A\u4F20\u5934\u50CF \u665A\u4E0A - \u4E0A\u4F20\u665A\u4E0A\u5934\u50CF\uFF08\u63A8\u8350\uFF09 \u2022 #\u5934\u50CF\u9884\u89C8 \u767D\u5929 - \u9884\u89C8\u767D\u5929\u5934\u50CF \u2022 #\u5934\u50CF\u9884\u89C8 \u665A\u4E0A - \u9884\u89C8\u665A\u4E0A\u5934\u50CF \u2022 #\u5934\u50CF\u4FE1\u606F - \u67E5\u770B\u5934\u50CF\u6587\u4EF6\u4FE1\u606F \u2022 #\u5220\u9664\u5934\u50CF \u767D\u5929 - \u5220\u9664\u767D\u5929\u5934\u50CF \u2022 #\u5220\u9664\u5934\u50CF \u665A\u4E0A - \u5220\u9664\u665A\u4E0A\u5934\u50CF \u2022 #\u8BBE\u7F6E\u767D\u5929\u5934\u50CF - \u901A\u8FC7\u8DEF\u5F84\u8BBE\u7F6E\u767D\u5929\u5934\u50CF \u2022 #\u8BBE\u7F6E\u665A\u4E0A\u5934\u50CF - \u901A\u8FC7\u8DEF\u5F84\u8BBE\u7F6E\u665A\u4E0A\u5934\u50CF \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u{1F4A1} \u4F7F\u7528\u8BF4\u660E\uFF1A 1. \u4F7F\u7528 #\u4E0A\u4F20\u5934\u50CF \u547D\u4EE4\u4E0A\u4F20\u56FE\u7247\uFF08\u63A8\u8350\uFF09 2. \u6216\u901A\u8FC7\u7F51\u9875\u914D\u7F6E\u754C\u9762\u8BBE\u7F6E\u6587\u4EF6\u8DEF\u5F84 3. \u8C03\u6574\u65F6\u95F4\u6BB5\uFF08\u9ED8\u8BA46-18\u70B9\u4E3A\u767D\u5929\uFF09 4. \u5F00\u542F\u81EA\u52A8\u5207\u6362\uFF0C\u6BCF\u5C0F\u65F6\u81EA\u52A8\u68C0\u67E5\u5207\u6362 5. \u4E5F\u53EF\u4EE5\u968F\u65F6\u624B\u52A8\u5207\u6362\u5934\u50CF \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \u26A0\uFE0F \u6CE8\u610F\uFF1A\u6240\u6709\u547D\u4EE4\u4EC5\u9650\u4E3B\u4EBA\u4F7F\u7528`; await e.reply(helpMsg); return true; }, { name: "\u5934\u50CF\u5E2E\u52A9" }); var setDayAvatar = karin.command("^(#)?\u8BBE\u7F6E\u767D\u5929\u5934\u50CF$", async (e) => { await e.reply("\u8BF7\u53D1\u9001\u8981\u8BBE\u7F6E\u4E3A\u767D\u5929\u5934\u50CF\u7684\u56FE\u7247\uFF0C\u6216\u53D1\u9001\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"); const response = await e.waitInput(6e4); if (!response) { await e.reply("\u274C \u8D85\u65F6\u672A\u6536\u5230\u56DE\u590D\uFF0C\u8BBE\u7F6E\u53D6\u6D88"); return true; } let avatarPath = ""; if (response.elements && response.elements.length > 0) { for (const element of response.elements) { if (element.type === "image") { try { const resourcePath = avatarConfig.getResourcePath(); if (!fs.existsSync(resourcePath)) { fs.mkdirSync(resourcePath, { recursive: true }); } avatarPath = path.join(resourcePath, "day-avatar.jpg"); if (element.url) { await downloadImage(element.url, avatarPath); avatarConfig.setDayAvatarPath(avatarPath); await e.reply("\u2705 \u767D\u5929\u5934\u50CF\u8BBE\u7F6E\u6210\u529F\uFF01"); } else { await e.reply("\u274C \u65E0\u6CD5\u83B7\u53D6\u56FE\u7247URL"); } } catch (error) { logger.error(`[\u5934\u50CF\u8BBE\u7F6E] \u4E0B\u8F7D\u767D\u5929\u5934\u50CF\u5931\u8D25: ${error}`); await e.reply("\u274C \u5934\u50CF\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"); } return true; } } } const pathText = response.raw_message || response.message; if (typeof pathText === "string" && pathText.trim()) { const inputPath = pathText.trim(); if (fs.existsSync(inputPath)) { const ext = path.extname(inputPath).toLowerCase(); if ([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"].includes(ext)) { avatarConfig.setDayAvatarPath(inputPath); await e.reply("\u2705 \u767D\u5929\u5934\u50CF\u8DEF\u5F84\u8BBE\u7F6E\u6210\u529F\uFF01"); } else { await e.reply("\u274C \u6587\u4EF6\u4E0D\u662F\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F"); } } else { await e.reply("\u274C \u6587\u4EF6\u8DEF\u5F84\u4E0D\u5B58\u5728"); } } else { await e.reply("\u274C \u8BF7\u53D1\u9001\u56FE\u7247\u6216\u6709\u6548\u7684\u6587\u4EF6\u8DEF\u5F84"); } return true; }, { name: "\u8BBE\u7F6E\u767D\u5929\u5934\u50CF", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u8BBE\u7F6E\u5934\u50CF\u54E6~" }); var setNightAvatar = karin.command("^(#)?\u8BBE\u7F6E\u665A\u4E0A\u5934\u50CF$", async (e) => { await e.reply("\u8BF7\u53D1\u9001\u8981\u8BBE\u7F6E\u4E3A\u665A\u4E0A\u5934\u50CF\u7684\u56FE\u7247\uFF0C\u6216\u53D1\u9001\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"); const response = await e.waitInput(6e4); if (!response) { await e.reply("\u274C \u8D85\u65F6\u672A\u6536\u5230\u56DE\u590D\uFF0C\u8BBE\u7F6E\u53D6\u6D88"); return true; } let avatarPath = ""; if (response.elements && response.elements.length > 0) { for (const element of response.elements) { if (element.type === "image") { try { const resourcePath = avatarConfig.getResourcePath(); if (!fs.existsSync(resourcePath)) { fs.mkdirSync(resourcePath, { recursive: true }); } avatarPath = path.join(resourcePath, "night-avatar.jpg"); if (element.url) { await downloadImage(element.url, avatarPath); avatarConfig.setNightAvatarPath(avatarPath); await e.reply("\u2705 \u665A\u4E0A\u5934\u50CF\u8BBE\u7F6E\u6210\u529F\uFF01"); } else { await e.reply("\u274C \u65E0\u6CD5\u83B7\u53D6\u56FE\u7247URL"); } } catch (error) { logger.error(`[\u5934\u50CF\u8BBE\u7F6E] \u4E0B\u8F7D\u665A\u4E0A\u5934\u50CF\u5931\u8D25: ${error}`); await e.reply("\u274C \u5934\u50CF\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5"); } return true; } } } const pathText = response.raw_message || response.message; if (typeof pathText === "string" && pathText.trim()) { const inputPath = pathText.trim(); if (fs.existsSync(inputPath)) { const ext = path.extname(inputPath).toLowerCase(); if ([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"].includes(ext)) { avatarConfig.setNightAvatarPath(inputPath); await e.reply("\u2705 \u665A\u4E0A\u5934\u50CF\u8DEF\u5F84\u8BBE\u7F6E\u6210\u529F\uFF01"); } else { await e.reply("\u274C \u6587\u4EF6\u4E0D\u662F\u652F\u6301\u7684\u56FE\u7247\u683C\u5F0F"); } } else { await e.reply("\u274C \u6587\u4EF6\u8DEF\u5F84\u4E0D\u5B58\u5728"); } } else { await e.reply("\u274C \u8BF7\u53D1\u9001\u56FE\u7247\u6216\u6709\u6548\u7684\u6587\u4EF6\u8DEF\u5F84"); } return true; }, { name: "\u8BBE\u7F6E\u665A\u4E0A\u5934\u50CF", perm: "master", authFailMsg: "\u53EA\u6709\u4E3B\u4EBA\u624D\u80FD\u8BBE\u7F6E\u5934\u50CF\u54E6~" }); async function downloadImage(url, savePath) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const buffer = await response.arrayBuffer(); fs.writeFileSync(savePath, Buffer.from(buffer)); logger.info(`[\u5934\u50CF\u4E0B\u8F7D] \u56FE\u7247\u5DF2\u4FDD\u5B58\u5230: ${savePath}`); } catch (error) { logger.error(`[\u5934\u50CF\u4E0B\u8F7D] \u4E0B\u8F7D\u5931\u8D25: ${error}`); throw error; } } export { autoSwitchAvatar, avatarHelp, avatarScheduleTask, avatarStatus, setDayAvatar, setNightAvatar, setTimeRange, switchToDayAvatar, switchToNightAvatar, toggleAutoSwitch };