gag / index.js
Jonell01's picture
Update index.js
93b21b9 verified
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const cron = require('node-cron');
const fs = require('fs');
const path = require('path');
const WebSocket = require('ws');
const app = express();
app.use(bodyParser.json());
const configPath = path.join(__dirname, 'database.json');
const usersPath = path.join(__dirname, 'users.json');
const favoritesPath = path.join(__dirname, 'favorites.json');
const lastSeenPath = path.join(__dirname, 'lastSeen.json');
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, JSON.stringify({
PAGE_ACCESS_TOKEN: 'EAAJ2oq2jZCIwBO1kFcU7DaPM7vfGZC16ncAbJzFZAuokeSK5dEdpQ1muBKWZBC6sUDrDrG9Mq4thZCcH6pqFYM1viCDOIjmZCEGHRokhKj3kIAt5uTToHoZBZAkJSozb5mODsk5xxE8NXG3ZAtv7lcQneeHkiUJmwdmPQsFeuslWZAwfZC3Hvz4ZCa5yCwiDIcEJX0we28820E5GKKGuJfCKXRPRVUVsJAZDZD',
VERIFY_TOKEN: 'ccprojects'
}));
}
if (!fs.existsSync(usersPath)) fs.writeFileSync(usersPath, JSON.stringify({}));
if (!fs.existsSync(favoritesPath)) fs.writeFileSync(favoritesPath, JSON.stringify({}));
if (!fs.existsSync(lastSeenPath)) fs.writeFileSync(lastSeenPath, JSON.stringify({}));
const config = JSON.parse(fs.readFileSync(configPath));
const PAGE_ACCESS_TOKEN = config.PAGE_ACCESS_TOKEN;
const VERIFY_TOKEN = config.VERIFY_TOKEN;
const activeSessions = new Map();
const lastSentCache = new Map();
let sharedWebSocket = null;
let keepAliveInterval = null;
const PH_TIMEZONE = "Asia/Manila";
function pad(n) {
return n < 10 ? "0" + n : n;
}
function getPHTime() {
return new Date(new Date().toLocaleString("en-US", { timeZone: PH_TIMEZONE }));
}
function getCountdown(target) {
const now = getPHTime();
const msLeft = target - now;
if (msLeft <= 0) return "00h 00m 00s";
const h = Math.floor(msLeft / 3.6e6);
const m = Math.floor((msLeft % 3.6e6) / 6e4);
const s = Math.floor((msLeft % 6e4) / 1000);
return `${pad(h)}h ${pad(m)}m ${pad(s)}s`;
}
function getNextRestocks() {
const now = getPHTime();
const timers = {};
const nextEgg = new Date(now);
nextEgg.setMinutes(now.getMinutes() < 30 ? 30 : 0);
if (now.getMinutes() >= 30) nextEgg.setHours(now.getHours() + 1);
nextEgg.setSeconds(0, 0);
timers.egg = getCountdown(nextEgg);
const next5 = new Date(now);
const nextM = Math.ceil((now.getMinutes() + (now.getSeconds() > 0 ? 1 : 0)) / 5) * 5;
next5.setMinutes(nextM === 60 ? 0 : nextM, 0, 0);
if (nextM === 60) next5.setHours(now.getHours() + 1);
timers.gear = timers.seed = getCountdown(next5);
const nextHoney = new Date(now);
nextHoney.setMinutes(now.getMinutes() < 30 ? 30 : 0);
if (now.getMinutes() >= 30) nextHoney.setHours(now.getHours() + 1);
nextHoney.setSeconds(0, 0);
timers.honey = getCountdown(nextHoney);
const next7 = new Date(now);
const totalHours = now.getHours() + now.getMinutes() / 60 + now.getSeconds() / 3600;
const next7h = Math.ceil(totalHours / 7) * 7;
next7.setHours(next7h, 0, 0, 0);
timers.cosmetics = getCountdown(next7);
return timers;
}
function formatValue(val) {
if (val >= 1_000_000) return `x${(val / 1_000_000).toFixed(1)}M`;
if (val >= 1_000) return `x${(val / 1_000).toFixed(1)}K`;
return `x${val}`;
}
function addEmoji(name) {
const emojis = {
"Common Egg": "๐Ÿฅš", "Uncommon Egg": "๐Ÿฃ", "Rare Egg": "๐Ÿณ", "Legendary Egg": "๐Ÿชบ", "Mythical Egg": "๐Ÿ”ฎ",
"Bug Egg": "๐Ÿชฒ", "Cleaning Spray": "๐Ÿงด", "Friendship Pot": "๐Ÿชด", "Watering Can": "๐Ÿšฟ", "Trowel": "๐Ÿ› ๏ธ",
"Recall Wrench": "๐Ÿ”ง", "Basic Sprinkler": "๐Ÿ’ง", "Advanced Sprinkler": "๐Ÿ’ฆ", "Godly Sprinkler": "โ›ฒ",
"Lightning Rod": "โšก", "Master Sprinkler": "๐ŸŒŠ", "Favorite Tool": "โค๏ธ", "Harvest Tool": "๐ŸŒพ", "Carrot": "๐Ÿฅ•",
"Strawberry": "๐Ÿ“", "Blueberry": "๐Ÿซ", "Orange Tulip": "๐ŸŒท", "Tomato": "๐Ÿ…", "Corn": "๐ŸŒฝ", "Daffodil": "๐ŸŒผ",
"Watermelon": "๐Ÿ‰", "Pumpkin": "๐ŸŽƒ", "Apple": "๐ŸŽ", "Bamboo": "๐ŸŽ", "Coconut": "๐Ÿฅฅ", "Cactus": "๐ŸŒต",
"Dragon Fruit": "๐Ÿˆ", "Mango": "๐Ÿฅญ", "Grape": "๐Ÿ‡", "Mushroom": "๐Ÿ„", "Pepper": "๐ŸŒถ๏ธ", "Cacao": "๐Ÿซ",
"Beanstalk": "๐ŸŒฑ", "Ember Lily": "๐Ÿต๏ธ", "Sugar Apple": "๐Ÿ"
};
return `${emojis[name] || ""} ${name}`;
}
function getTimeAgo(date) {
const now = getPHTime();
const diff = now - new Date(date);
const sec = Math.floor(diff / 1000);
const min = Math.floor(sec / 60);
const hour = Math.floor(min / 60);
const day = Math.floor(hour / 24);
if (sec < 60) return `${sec}s ago`;
if (min < 60) return `${min}m ago`;
if (hour < 24) return `${hour}h ago`;
return `${day}d ago`;
}
function cleanText(text) {
return text.trim().toLowerCase();
}
function loadFavorites() {
try {
return JSON.parse(fs.readFileSync(favoritesPath));
} catch {
return {};
}
}
function saveFavorites(favorites) {
fs.writeFileSync(favoritesPath, JSON.stringify(favorites));
}
function loadLastSeen() {
try {
return JSON.parse(fs.readFileSync(lastSeenPath));
} catch {
return {};
}
}
function saveLastSeen(lastSeen) {
fs.writeFileSync(lastSeenPath, JSON.stringify(lastSeen));
}
function updateLastSeen(category, items) {
const lastSeen = loadLastSeen();
if (!lastSeen[category]) lastSeen[category] = {};
const now = new Date().toISOString();
items.forEach(item => {
lastSeen[category][item.name] = now;
});
saveLastSeen(lastSeen);
}
function ensureWebSocketConnection() {
if (sharedWebSocket && sharedWebSocket.readyState === WebSocket.OPEN) return;
sharedWebSocket = new WebSocket("wss://gagstock.gleeze.com");
sharedWebSocket.on("open", () => {
keepAliveInterval = setInterval(() => {
if (sharedWebSocket.readyState === WebSocket.OPEN) {
sharedWebSocket.send("ping");
}
}, 10000);
});
sharedWebSocket.on("message", async (data) => {
try {
const payload = JSON.parse(data);
if (payload.status !== "success") return;
const stock = payload.data;
const stockData = {
gear: stock.gear,
seed: stock.seed,
egg: stock.egg,
cosmetics: stock.cosmetics,
event: stock.honey,
};
updateLastSeen("gear", stockData.gear.items);
updateLastSeen("seed", stockData.seed.items);
updateLastSeen("egg", stockData.egg.items);
updateLastSeen("cosmetics", stockData.cosmetics.items);
updateLastSeen("event", stockData.event.items);
const favorites = loadFavorites();
for (const [senderId] of activeSessions.entries()) {
const userFavorites = favorites[senderId] || [];
let sections = [];
let matchCount = 0;
const checkAndAdd = (label, section, useEmoji) => {
const items = section.items || [];
const matchedItems = userFavorites.length > 0
? items.filter(i => userFavorites.includes(cleanText(i.name)))
: items;
if (userFavorites.length > 0 && matchedItems.length === 0) return false;
matchCount += matchedItems.length;
const formattedItems = matchedItems.map(i =>
`- ${useEmoji ? addEmoji(i.name) : i.name}: ${formatValue(i.quantity)}`
).join("\n");
sections.push(`${label}:\n${formattedItems}\nโณ Restock In: ${section.countdown}`);
return true;
};
checkAndAdd("๐Ÿ› ๏ธ ๐—š๐—ฒ๐—ฎ๐—ฟ", stockData.gear, true);
checkAndAdd("๐ŸŒฑ ๐—ฆ๐—ฒ๐—ฒ๐—ฑ๐˜€", stockData.seed, true);
checkAndAdd("๐Ÿฅš ๐—˜๐—ด๐—ด๐˜€", stockData.egg, true);
checkAndAdd("๐ŸŽจ ๐—–๐—ผ๐˜€๐—บ๐—ฒ๐˜๐—ถ๐—ฐ๐˜€", stockData.cosmetics, false);
checkAndAdd("๐ŸŽ‰ ๐—˜๐˜ƒ๐—ฒ๐—ป๐˜", stockData.event, false);
if (userFavorites.length > 0 && matchCount === 0) continue;
if (sections.length === 0) continue;
const updatedAt = getPHTime().toLocaleString("en-PH", {
hour: "numeric", minute: "numeric", second: "numeric",
hour12: true, day: "2-digit", month: "short", year: "numeric"
});
const weather = await axios.get("https://growagardenstock.com/api/stock/weather")
.then(res => res.data)
.catch(() => null);
const weatherInfo = weather
? `๐ŸŒค๏ธ ๐—ช๐—ฒ๐—ฎ๐˜๐—ต๐—ฒ๐—ฟ: ${weather.icon} ${weather.weatherType}\n๐Ÿ“‹ ${weather.description}\n๐ŸŽฏ ${weather.cropBonuses}\n`
: "";
const title = userFavorites.length > 0
? `โ™ฅ๏ธ ${matchCount} ๐—™๐—ฎ๐˜ƒ๐—ผ๐—ฟ๐—ถ๐˜๐—ฒ ๐—ถ๐˜๐—ฒ๐—บ${matchCount > 1 ? "s" : ""} ๐—™๐—ผ๐˜‚๐—ป๐—ฑ!`
: "๐ŸŒพ ๐—š๐—ฟ๐—ผ๐˜„ ๐—” ๐—š๐—ฎ๐—ฟ๐—ฑ๐—ฒ๐—ป โ€” ๐—ง๐—ฟ๐—ฎ๐—ฐ๐—ธ๐—ฒ๐—ฟ";
const messageKey = JSON.stringify({ title, sections, weatherInfo, updatedAt });
const lastSent = lastSentCache.get(senderId);
if (lastSent === messageKey) continue;
lastSentCache.set(senderId, messageKey);
await sendMessage(senderId,
`${title}\n\n${sections.join("\n\n")}\n\n${weatherInfo}๐Ÿ“… Updated at (PH): ${updatedAt}`
);
}
} catch (error) {
console.error('Error processing WebSocket message:', error);
}
});
sharedWebSocket.on("close", () => {
clearInterval(keepAliveInterval);
sharedWebSocket = null;
setTimeout(ensureWebSocketConnection, 3000);
});
sharedWebSocket.on("error", () => {
sharedWebSocket?.close();
});
}
async function sendTyping(recipientId) {
try {
await axios.post(`https://graph.facebook.com/v12.0/me/messages?access_token=${PAGE_ACCESS_TOKEN}`, {
recipient: { id: recipientId },
sender_action: 'typing_on'
});
} catch (error) {
console.error('Error sending typing indicator:', error.message);
}
}
async function getStockData() {
try {
const [stockResponse, updateResponse] = await Promise.all([
axios.get('https://kenlie.top/api/gag/stocks/'),
axios.get('https://jonell01-reuploadotherhruhh.hf.space/grow')
]);
return {
stockData: stockResponse.data,
lastUpdated: updateResponse.data.lastUpdated
};
} catch (error) {
console.error('Error fetching stock data:', error.message);
return null;
}
}
async function getWeatherData() {
try {
const response = await axios.get('https://kenlie.top/api/gag/weather/');
return response.data;
} catch (error) {
console.error('Error fetching weather data:', error.message);
return null;
}
}
function formatStockMessage(data) {
if (!data || !data.stockData.status) return "โš ๏ธ Could not fetch stock data";
let message = `๐Ÿ›’ ๐—–๐—จ๐—ฅ๐—ฅ๐—˜๐—ก๐—ง ๐—ฆ๐—ง๐—ข๐—–๐—ž ๐—จ๐—ฃ๐——๐—”๐—ง๐—˜๐—ฆ ๐Ÿ›’\n`;
message += `๐Ÿ•’ LAST UPDATED: ${new Date(data.lastUpdated).toLocaleString()}\n\n`;
const stockData = data.stockData.response;
const categories = {
gearStock: '๐Ÿ› ๏ธ ๐—š๐—˜๐—”๐—ฅ',
eggStock: '๐Ÿฅš ๐—˜๐—š๐—š๐—ฆ',
seedsStock: '๐ŸŒฑ ๐—ฆ๐—˜๐—˜๐——๐—ฆ',
easterStock: '๐Ÿฐ ๐—˜๐—”๐—ฆ๐—ง๐—˜๐—ฅ',
nightStock: '๐ŸŒ™ ๐—ก๐—œ๐—š๐—›๐—ง',
honeyStock: '๐Ÿฏ ๐—›๐—ข๐—ก๐—˜๐—ฌ',
cosmeticsStock: '๐Ÿ’„ ๐—–๐—ข๐—ฆ๐— ๐—˜๐—ง๐—œ๐—–๐—ฆ '
};
for (const [categoryKey, categoryName] of Object.entries(categories)) {
if (stockData[categoryKey] && stockData[categoryKey].length > 0) {
message += `${categoryName}:\n`;
stockData[categoryKey].forEach(item => {
message += `โ€ข ${item.name}: ${item.value}\n`;
});
message += '\n';
}
}
return message;
}
function formatWeatherMessage(weatherData) {
if (!weatherData || !weatherData.status) return "โš ๏ธ Could not fetch weather data";
const weatherEmojis = {
rain: '๐ŸŒง๏ธ ๐—ฅ๐—”๐—œ๐—ก',
snow: 'โ„๏ธ ๐—ฆ๐—ก๐—ข๐—ช',
thunderstorm: 'โšก ๐—ง๐—›๐—จ๐—ก๐——๐—˜๐—ฅ๐—ฆ๐—ง๐—ข๐—ฅ๐— ',
bloodnight: '๐Ÿฉธ ๐—•๐—Ÿ๐—ข๐—ข๐——๐—ก๐—œ๐—š๐—›๐—ง',
meteorshower: 'โ˜„๏ธ ๐— ๐—˜๐—ง๐—˜๐—ข๐—ฅ ๐—ฆ๐—›๐—ข๐—ช๐—˜๐—ฅ',
disco: '๐Ÿชฉ ๐——๐—œ๐—ฆ๐—–๐—ข',
jandelstorm: '๐Ÿ•ฏ๏ธ ๐—๐—”๐—ก๐——๐—˜๐—Ÿ๐—ฆ๐—ง๐—ข๐—ฅ๐— ',
blackhole: '๐Ÿ•ณ๏ธ ๐—•๐—Ÿ๐—”๐—–๐—ž๐—›๐—ข๐—Ÿ๐—˜',
frost: 'โ„๏ธ ๐—™๐—ฅ๐—ข๐—ฆ๐—ง '
};
let message = 'โ›… ๐—–๐—จ๐—ฅ๐—ฅ๐—˜๐—ก๐—ง ๐—ช๐—˜๐—”๐—ง๐—›๐—˜๐—ฅ ๐—–๐—ข๐—ก๐——๐—œ๐—ง๐—œ๐—ข๐—ก๐—ฆ\n\n';
const activeEvents = [];
for (const [event, data] of Object.entries(weatherData.response)) {
if (data.active) {
activeEvents.push(`${weatherEmojis[event] || '๐ŸŒ€'} ${event.toUpperCase()}`);
}
}
if (activeEvents.length === 0) {
message += "โ˜€๏ธ NO ACTIVE WEATHER EVENTS\n";
} else {
message += "๐ŸŸข ๐—”๐—–๐—ง๐—œ๐—ฉ๐—˜ ๐—ช๐—˜๐—”๐—ง๐—›๐—˜๐—ฅ ๐—˜๐—ฉ๐—˜๐—ก๐—ง๐—ฆ:\n";
message += activeEvents.join('\n');
}
return message;
}
async function sendMessage(recipientId, messageText) {
try {
await axios.post(`https://graph.facebook.com/v12.0/me/messages?access_token=${PAGE_ACCESS_TOKEN}`, {
recipient: { id: recipientId },
message: { text: messageText }
});
} catch (error) {
console.error('Error sending message:', error.message);
}
}
function loadUserPreferences() {
try {
return JSON.parse(fs.readFileSync(usersPath));
} catch {
return {};
}
}
function saveUserPreferences(preferences) {
fs.writeFileSync(usersPath, JSON.stringify(preferences));
}
function setupUserNotification(recipientId, intervalMinutes = 5) {
const preferences = loadUserPreferences();
if (preferences[recipientId]?.intervalId) {
clearInterval(preferences[recipientId].intervalId);
}
const intervalId = setInterval(async () => {
const data = await getStockData();
if (data) {
await sendMessage(recipientId, formatStockMessage(data));
}
}, intervalMinutes * 60 * 1000);
preferences[recipientId] = {
notificationsOn: true,
interval: intervalMinutes,
intervalId: intervalId
};
saveUserPreferences(preferences);
}
function turnOffNotifications(recipientId) {
const preferences = loadUserPreferences();
if (preferences[recipientId]?.intervalId) {
clearInterval(preferences[recipientId].intervalId);
}
preferences[recipientId] = {
notificationsOn: false,
interval: null,
intervalId: null
};
saveUserPreferences(preferences);
}
async function handleGagStockCommand(senderId, args) {
const subcmd = args[0]?.toLowerCase();
if (subcmd === "fav") {
const action = args[1]?.toLowerCase();
const input = args.slice(2).join(" ").split("|").map(i => cleanText(i)).filter(Boolean);
if (!action || !["add", "remove"].includes(action) || input.length === 0) {
return await sendMessage(senderId, "๐Ÿ“Œ Usage: /gagstock fav add/remove Item1 | Item2");
}
const favorites = loadFavorites();
const userFavorites = favorites[senderId] || [];
const updated = new Set(userFavorites);
for (const name of input) {
if (action === "add") updated.add(name);
else if (action === "remove") updated.delete(name);
}
favorites[senderId] = Array.from(updated);
saveFavorites(favorites);
return await sendMessage(senderId, `โœ… Favorite list updated: ${Array.from(updated).join(", ") || "(empty)"}`);
}
if (subcmd === "lastseen") {
const filters = args.slice(1).join(" ").split("|").map(c => c.trim().toLowerCase()).filter(Boolean);
const categories = filters.length > 0 ? filters : ["gear", "seed", "egg", "cosmetics", "event"];
const lastSeen = loadLastSeen();
let result = [];
for (const cat of categories) {
const entries = lastSeen[cat];
if (!entries || Object.keys(entries).length === 0) continue;
const list = Object.entries(entries)
.sort((a, b) => new Date(b[1]) - new Date(a[1]))
.map(([name, date]) => `โ€ข ${name}: ${getTimeAgo(date)}`);
result.push(`๐Ÿ”น ${cat.toUpperCase()} (${list.length})\n${list.join("\n")}`);
}
if (result.length === 0) {
return await sendMessage(senderId, "โš ๏ธ No last seen data found for the selected category.");
}
return await sendMessage(senderId, `๐Ÿ“ฆ ๐—Ÿ๐—ฎ๐˜€๐˜ ๐—ฆ๐—ฒ๐—ฒ๐—ป ๐—œ๐˜๐—ฒ๐—บ๐˜€\n\n${result.join("\n\n")}`);
}
if (subcmd === "off") {
if (!activeSessions.has(senderId)) {
return await sendMessage(senderId, "โš ๏ธ You don't have an active gagstock session.");
}
activeSessions.delete(senderId);
lastSentCache.delete(senderId);
return await sendMessage(senderId, "๐Ÿ›‘ Gagstock tracking stopped.");
}
if (subcmd !== "on") {
return await sendMessage(senderId,
"๐Ÿ“Œ Usage:\nโ€ข /gagstock on\nโ€ข /gagstock fav add Carrot | Watering Can\nโ€ข /gagstock lastseen gear | seed\nโ€ข /gagstock off"
);
}
if (activeSessions.has(senderId)) {
return await sendMessage(senderId, "๐Ÿ“ก You're already tracking Gagstock. Use /gagstock off to stop.");
}
activeSessions.set(senderId, true);
await sendMessage(senderId, "โœ… Gagstock tracking started via WebSocket!");
ensureWebSocketConnection();
}
app.get('/webhook', (req, res) => {
if (req.query['hub.mode'] === 'subscribe' && req.query['hub.verify_token'] === VERIFY_TOKEN) {
res.status(200).send(req.query['hub.challenge']);
} else {
res.sendStatus(403);
}
});
app.post('/webhook', async (req, res) => {
if (req.body.object === 'page') {
for (const entry of req.body.entry) {
for (const event of entry.messaging) {
if (event.message?.text) {
await handleMessage(event.sender.id, event.message.text);
}
}
}
res.status(200).send('EVENT_RECEIVED');
} else {
res.sendStatus(404);
}
});
async function handleMessage(senderId, messageText) {
const command = messageText.trim().toLowerCase();
await sendTyping(senderId);
if (command === '/help') {
const helpMessage = `๐ŸŒฑ ๐—š๐—ฅ๐—ข๐—ช ๐—” ๐—š๐—”๐—ฅ๐——๐—˜๐—ก ๐—•๐—ข๐—ง ๐—›๐—˜๐—Ÿ๐—ฃ ๐ŸŒฑ\n\n` +
`๐Ÿ›’ /๐˜€๐˜๐—ผ๐—ฐ๐—ธ - Get current stock information\n` +
`โ›… /๐˜„๐—ฒ๐—ฎ๐˜๐—ต๐—ฒ๐—ฟ - Get current weather conditions\n` +
`๐ŸŒพ /๐—ด๐—ฎ๐—ด๐˜€๐˜๐—ผ๐—ฐ๐—ธ - Real-time stock tracking\n` +
` โ€ข /๐—ด๐—ฎ๐—ด๐˜€๐˜๐—ผ๐—ฐ๐—ธ ๐—ผ๐—ป - Start tracking\n` +
` โ€ข /๐—ด๐—ฎ๐—ด๐˜€๐˜๐—ผ๐—ฐ๐—ธ ๐—ผ๐—ณ๐—ณ - Stop tracking\n` +
` โ€ข /๐—ด๐—ฎ๐—ด๐˜€๐˜๐—ผ๐—ฐ๐—ธ ๐—ณ๐—ฎ๐˜ƒ ๐—ฎ๐—ฑ๐—ฑ ๐—ถ๐˜๐—ฒ๐—บ - Add favorite\n` +
` โ€ข /๐—ด๐—ฎ๐—ด๐˜€๐˜๐—ผ๐—ฐ๐—ธ ๐—น๐—ฎ๐˜€๐˜๐˜€๐—ฒ๐—ฒ๐—ป - View last seen items\n` +
`๐Ÿ”” /๐—ป๐—ผ๐˜๐—ถ ๐—ผ๐—ป - Enable stock notifications\n` +
`๐Ÿ”• /๐—ป๐—ผ๐˜๐—ถ ๐—ผ๐—ณ๐—ณ - Disable notifications\n` +
`โฑ๏ธ /๐—ป๐—ผ๐˜๐—ถ ๐—ผ๐—ป [๐—บ๐—ถ๐—ป๐˜‚๐˜๐—ฒ๐˜€] - Set notification interval\n` +
`โ„น๏ธ /๐—ต๐—ฒ๐—น๐—ฝ - Show this help message`;
await sendMessage(senderId, helpMessage);
}
else if (command === '/stock') {
const data = await getStockData();
await sendMessage(senderId, data ? formatStockMessage(data) : 'โš ๏ธ Could not fetch stock data');
}
else if (command === '/weather') {
const weatherData = await getWeatherData();
await sendMessage(senderId, weatherData ? formatWeatherMessage(weatherData) : 'โš ๏ธ Could not fetch weather data');
}
else if (command.startsWith('/gagstock')) {
const args = command.split(' ').slice(1);
await handleGagStockCommand(senderId, args);
}
else if (command.startsWith('/noti')) {
const parts = command.split(' ');
if (parts[1] === 'on') {
const interval = parts[2] ? parseInt(parts[2]) : 5;
if (isNaN(interval) || interval < 1) {
await sendMessage(senderId, 'โš ๏ธ Please provide valid minutes (e.g., /noti on 5)');
return;
}
setupUserNotification(senderId, interval);
await sendMessage(senderId, `๐Ÿ”” Notifications enabled! Updates every ${interval} minutes.`);
}
else if (parts[1] === 'off') {
turnOffNotifications(senderId);
await sendMessage(senderId, '๐Ÿ”• Notifications disabled!');
}
else {
await sendMessage(senderId, 'โš ๏ธ Use /noti on, /noti off, or /noti on [minutes]');
}
}
else {
await sendMessage(senderId, '๐ŸŒฟ Welcome! Grow a Garden Notifier Stocks User! Type /help for commands.');
}
}
loadUserPreferences();
const PORT = process.env.PORT || 7860;
app.listen(PORT, () => {
console.log(`Bot running on port ${PORT}`);
});