Redo
This commit is contained in:
parent
cddc77e520
commit
eeaf817f56
422
main.js
422
main.js
|
@ -1,233 +1,287 @@
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
|
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
|
||||||
const fs = require('fs');
|
const sqlite3 = require('sqlite3').verbose();
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
let priceHistory = {
|
|
||||||
currentPrice: 0,
|
|
||||||
prices: [{
|
|
||||||
time: Date.now(),
|
|
||||||
price: 0,
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
|
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
|
||||||
});
|
});
|
||||||
|
|
||||||
const solanaPriceChannelId = process.env.SOLANA_PRICE_CHANNEL_ID;
|
const PRICE_CHECK_INTERVAL = 60000;
|
||||||
const announcementsChannelId = process.env.ANNOUNCEMENTS_CHANNEL_ID;
|
const PRICE_INCREASE_THRESHOLD = 2.5;
|
||||||
const solanaDataFile = './data/solana.json';
|
const DB_PATH = path.join(__dirname, 'data', 'solana.db');
|
||||||
let lastAnnouncedPrice;
|
|
||||||
let lastPriceMessageId;
|
|
||||||
|
|
||||||
client.once('ready', async () => {
|
const db = new sqlite3.Database(DB_PATH, (err) => {
|
||||||
console.log('Bot is online!');
|
if (err) console.error('Database opening error: ', err);
|
||||||
let solanaData = readSolanaData();
|
initializeDatabase();
|
||||||
if (solanaData) {
|
|
||||||
priceHistory = solanaData;
|
|
||||||
lastAnnouncedPrice = solanaData.lastAnnouncedPrice;
|
|
||||||
lastPriceMessageId = solanaData.lastPriceMessageId;
|
|
||||||
}
|
|
||||||
immediatePriceCheckAndAnnounce();
|
|
||||||
checkPriceContinuously();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function initializeDatabase() {
|
||||||
|
db.serialize(() => {
|
||||||
|
db.run(`CREATE TABLE IF NOT EXISTS price_history (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
timestamp INTEGER NOT NULL,
|
||||||
|
price REAL NOT NULL
|
||||||
|
)`);
|
||||||
|
|
||||||
|
db.run(`CREATE TABLE IF NOT EXISTS bot_state (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT NOT NULL
|
||||||
|
)`);
|
||||||
|
|
||||||
|
db.run('CREATE INDEX IF NOT EXISTS idx_timestamp ON price_history(timestamp)');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchSolanaPrice() {
|
async function fetchSolanaPrice() {
|
||||||
const cryptocompareApiUrl = 'https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD';
|
|
||||||
try {
|
try {
|
||||||
const fetch = (await import('node-fetch')).default;
|
const fetch = (await import('node-fetch')).default;
|
||||||
const response = await fetch(cryptocompareApiUrl);
|
const response = await fetch('https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD');
|
||||||
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
return parseFloat(data.USD).toFixed(2);
|
return parseFloat(data.USD).toFixed(2);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching Solana price:', error);
|
console.error('Error fetching Solana price:', error);
|
||||||
setTimeout(fetchSolanaPriceAndUpdateHistory, 5 * 60 * 1000);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function pruneOldData() {
|
function savePriceData(price) {
|
||||||
const sixHoursInMilliseconds = 6 * 60 * 60 * 1000;
|
return new Promise((resolve, reject) => {
|
||||||
const oneDayInMilliseconds = 24 * 60 * 60 * 1000;
|
const timestamp = Date.now();
|
||||||
const cutoffTime1Day = Date.now() - oneDayInMilliseconds;
|
db.run('INSERT INTO price_history (timestamp, price) VALUES (?, ?)',
|
||||||
|
[timestamp, price],
|
||||||
|
(err) => err ? reject(err) : resolve());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
priceHistory.prices = priceHistory.prices.filter(pricePoint => pricePoint.time > cutoffTime1Day);
|
function getLastAnnouncedPrice() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
db.get('SELECT value FROM bot_state WHERE key = "lastAnnouncedPrice"',
|
||||||
|
(err, row) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error getting last announced price:', err);
|
||||||
|
resolve(null);
|
||||||
|
} else {
|
||||||
|
resolve(row ? parseFloat(row.value) : null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (priceHistory.prices.length < (sixHoursInMilliseconds / (60 * 1000))) {
|
function updateLastAnnouncedPrice(price) {
|
||||||
console.warn("Warning: Not enough data points for accurate 6-hour calculations.");
|
return new Promise((resolve, reject) => {
|
||||||
}
|
db.run('INSERT OR REPLACE INTO bot_state (key, value) VALUES (?, ?)',
|
||||||
if (priceHistory.prices.length < (oneDayInMilliseconds / (60 * 1000))) {
|
['lastAnnouncedPrice', price.toString()],
|
||||||
console.warn("Warning: Not enough data points for accurate 1-day calculations.");
|
(err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error updating last announced price:', err);
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeBasedPrice(minutesAgo) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timestamp = Date.now() - (minutesAgo * 60 * 1000);
|
||||||
|
db.get(
|
||||||
|
`SELECT price FROM price_history
|
||||||
|
WHERE timestamp <= ?
|
||||||
|
ORDER BY timestamp DESC LIMIT 1`,
|
||||||
|
[timestamp],
|
||||||
|
(err, row) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(`Error getting price from ${minutesAgo} minutes ago:`, err);
|
||||||
|
resolve(null);
|
||||||
|
} else {
|
||||||
|
resolve(row?.price || null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function calculateChanges(currentPrice) {
|
||||||
|
try {
|
||||||
|
const [oneMinAgo, fiveMinAgo, oneHourAgo, sixHourAgo, oneDayAgo] = await Promise.all([
|
||||||
|
getTimeBasedPrice(1),
|
||||||
|
getTimeBasedPrice(5),
|
||||||
|
getTimeBasedPrice(60),
|
||||||
|
getTimeBasedPrice(360),
|
||||||
|
getTimeBasedPrice(1440)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const calculateChange = (oldPrice) => {
|
||||||
|
if (!oldPrice) return { percent: 0, dollar: 0 };
|
||||||
|
const dollarChange = currentPrice - oldPrice;
|
||||||
|
const percentChange = (dollarChange / oldPrice) * 100;
|
||||||
|
return { percent: percentChange, dollar: dollarChange };
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
oneMin: calculateChange(oneMinAgo),
|
||||||
|
fiveMin: calculateChange(fiveMinAgo),
|
||||||
|
oneHour: calculateChange(oneHourAgo),
|
||||||
|
sixHour: calculateChange(sixHourAgo),
|
||||||
|
oneDay: calculateChange(oneDayAgo)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error calculating changes:', error);
|
||||||
|
return {
|
||||||
|
oneMin: { percent: 0, dollar: 0 },
|
||||||
|
fiveMin: { percent: 0, dollar: 0 },
|
||||||
|
oneHour: { percent: 0, dollar: 0 },
|
||||||
|
sixHour: { percent: 0, dollar: 0 },
|
||||||
|
oneDay: { percent: 0, dollar: 0 }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchSolanaPriceAndUpdateHistory() {
|
async function createPriceEmbed(currentPrice, changes) {
|
||||||
const currentPrice = await fetchSolanaPrice();
|
|
||||||
if (currentPrice) {
|
|
||||||
pruneOldData();
|
|
||||||
|
|
||||||
priceHistory.prices.push({ time: Date.now(), price: currentPrice });
|
|
||||||
priceHistory.currentPrice = currentPrice;
|
|
||||||
|
|
||||||
saveSolanaData(priceHistory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function immediatePriceCheckAndAnnounce() {
|
|
||||||
const solanaData = readSolanaData();
|
|
||||||
const lastKnownPrice = solanaData ? solanaData.price : null;
|
|
||||||
const currentPrice = fetchSolanaPrice();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
function calculateChanges() {
|
|
||||||
const latestPrice = parseFloat(priceHistory.currentPrice);
|
|
||||||
let oneMinChange = { percent: 0, dollar: 0 };
|
|
||||||
let fiveMinChange = { percent: 0, dollar: 0 };
|
|
||||||
let oneHourChange = { percent: 0, dollar: 0 };
|
|
||||||
let sixHourChange = { percent: 0, dollar: 0 }
|
|
||||||
let oneDayChange = { percent: 0, dollar: 0 };
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
function findPriceAgo(minutesAgo) {
|
|
||||||
const targetTime = now - minutesAgo * 60 * 1000;
|
|
||||||
return priceHistory.prices.reduce((prev, curr) => {
|
|
||||||
return Math.abs(curr.time - targetTime) < Math.abs(prev.time - targetTime) ? curr : prev;
|
|
||||||
}, priceHistory.prices[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priceHistory.prices.length >= 2) {
|
|
||||||
const oneMinAgoPrice = parseFloat(findPriceAgo(1).price);
|
|
||||||
oneMinChange.percent = ((latestPrice - oneMinAgoPrice) / oneMinAgoPrice) * 100;
|
|
||||||
oneMinChange.dollar = latestPrice - oneMinAgoPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priceHistory.prices.length >= 6) {
|
|
||||||
const fiveMinAgoPrice = parseFloat(findPriceAgo(5).price);
|
|
||||||
fiveMinChange.percent = ((latestPrice - fiveMinAgoPrice) / fiveMinAgoPrice) * 100;
|
|
||||||
fiveMinChange.dollar = latestPrice - fiveMinAgoPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priceHistory.prices.length >= 61) {
|
|
||||||
const oneHourAgoPrice = parseFloat(findPriceAgo(60).price);
|
|
||||||
oneHourChange.percent = ((latestPrice - oneHourAgoPrice) / oneHourAgoPrice) * 100;
|
|
||||||
oneHourChange.dollar = latestPrice - oneHourAgoPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priceHistory.prices.length >= 1440) {
|
|
||||||
const oneDayAgoPrice = parseFloat(findPriceAgo(1440).price);
|
|
||||||
oneDayChange.percent = ((latestPrice - oneDayAgoPrice) / oneDayAgoPrice) * 100;
|
|
||||||
oneDayChange.dollar = latestPrice - oneDayAgoPrice;
|
|
||||||
} else {
|
|
||||||
console.log("Insufficient data for 1-day change calculation.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priceHistory.prices.length >= 360) {
|
|
||||||
const sixHourAgoPrice = parseFloat(findPriceAgo(360).price);
|
|
||||||
sixHourChange.percent = ((latestPrice - sixHourAgoPrice) / sixHourAgoPrice) * 100;
|
|
||||||
sixHourChange.dollar = latestPrice - sixHourAgoPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange };
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendNewPriceMessage(embed) {
|
|
||||||
const sentMessage = await solanaPriceChannel.send({ embeds: [embed] });
|
|
||||||
lastPriceMessageId = sentMessage.id;
|
|
||||||
|
|
||||||
saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function sendNewPriceMessage(solanaPriceChannel, embed) {
|
|
||||||
const sentMessage = await solanaPriceChannel.send({ embeds: [embed] });
|
|
||||||
lastPriceMessageId = sentMessage.id;
|
|
||||||
|
|
||||||
saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id });
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkPriceContinuously() {
|
|
||||||
await fetchSolanaPriceAndUpdateHistory();
|
|
||||||
const { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange } = calculateChanges();
|
|
||||||
|
|
||||||
console.log(`Current Price: ${priceHistory.currentPrice}`);
|
|
||||||
|
|
||||||
const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
|
const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
return new EmbedBuilder()
|
||||||
.setColor(`#${randomColor}`)
|
.setColor(`#${randomColor}`)
|
||||||
.setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png')
|
.setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png')
|
||||||
.setTitle('Solana (SOL) Price Update')
|
.setTitle('Solana (SOL) Price Update')
|
||||||
.setURL('https://coinmarketcap.com/currencies/solana/')
|
.setURL('https://coinmarketcap.com/currencies/solana/')
|
||||||
.setDescription(`**Current Price: \`$${priceHistory.currentPrice}\`**`)
|
.setDescription(`**Current Price: \`$${currentPrice}\`**`)
|
||||||
.addFields([
|
.addFields([
|
||||||
{ name: '💰 Current Price', value: `**\`$${priceHistory.currentPrice}\`**`, inline: false },
|
{ name: '💰 Current Price', value: `**\`$${currentPrice}\`**`, inline: false },
|
||||||
{ name: '1 Minute Change', value: `${oneMinChange.percent.toFixed(2)}% (${oneMinChange.dollar.toFixed(2)} USD)`, inline: true },
|
{ name: '1 Minute Change', value: `${changes.oneMin.percent.toFixed(2)}% (${changes.oneMin.dollar.toFixed(2)} USD)`, inline: true },
|
||||||
{ name: '5 Minute Change', value: `${fiveMinChange.percent.toFixed(2)}% (${fiveMinChange.dollar.toFixed(2)} USD)`, inline: true },
|
{ name: '5 Minute Change', value: `${changes.fiveMin.percent.toFixed(2)}% (${changes.fiveMin.dollar.toFixed(2)} USD)`, inline: true },
|
||||||
{ name: '1 Hour Change', value: `${oneHourChange.percent.toFixed(2)}% (${oneHourChange.dollar.toFixed(2)} USD)`, inline: true },
|
{ name: '1 Hour Change', value: `${changes.oneHour.percent.toFixed(2)}% (${changes.oneHour.dollar.toFixed(2)} USD)`, inline: true },
|
||||||
{ name: '6 Hour Change', value: `${sixHourChange.percent.toFixed(2)}% (${sixHourChange.dollar.toFixed(2)} USD)`, inline: true },
|
{ name: '6 Hour Change', value: `${changes.sixHour.percent.toFixed(2)}% (${changes.sixHour.dollar.toFixed(2)} USD)`, inline: true },
|
||||||
{ name: '1 Day Change', value: `${oneDayChange.percent.toFixed(2)}% (${oneDayChange.dollar.toFixed(2)} USD)`, inline: true }
|
{ name: '1 Day Change', value: `${changes.oneDay.percent.toFixed(2)}% (${changes.oneDay.dollar.toFixed(2)} USD)`, inline: true }
|
||||||
])
|
])
|
||||||
.setTimestamp()
|
.setTimestamp()
|
||||||
.setImage(process.env.IMAGE_URL);
|
.setImage(process.env.IMAGE_URL);
|
||||||
|
|
||||||
const solanaPriceChannel = await client.channels.fetch(solanaPriceChannelId);
|
|
||||||
|
|
||||||
if (lastPriceMessageId) {
|
|
||||||
try {
|
|
||||||
const message = await solanaPriceChannel.messages.fetch(lastPriceMessageId);
|
|
||||||
await message.edit({ embeds: [embed] });
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error updating price message, sending a new one:', error);
|
|
||||||
sendNewPriceMessage(solanaPriceChannel, embed);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log('No lastPriceMessageId found, sending a new message.');
|
|
||||||
sendNewPriceMessage(solanaPriceChannel, embed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastAnnouncedPrice !== null && (parseFloat(priceHistory.currentPrice) - lastAnnouncedPrice >= 2.5)) {
|
|
||||||
const announcementsChannel = await client.channels.fetch(announcementsChannelId);
|
|
||||||
await announcementsChannel.send(`@everyone Solana price has increased significantly! Current price: $${priceHistory.currentPrice}`);
|
|
||||||
lastAnnouncedPrice = parseFloat(priceHistory.currentPrice);
|
|
||||||
saveSolanaData({ ...priceHistory, lastAnnouncedPrice });
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(checkPriceContinuously, 60000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSolanaData(data) {
|
async function getMessageId() {
|
||||||
const dir = path.dirname(solanaDataFile);
|
return new Promise((resolve) => {
|
||||||
if (!fs.existsSync(dir)) {
|
db.get('SELECT value FROM bot_state WHERE key = "priceMessageId"',
|
||||||
fs.mkdirSync(dir, { recursive: true });
|
(err, row) => {
|
||||||
}
|
if (err) {
|
||||||
|
console.error('Error getting message ID:', err);
|
||||||
const dataToSave = {
|
resolve(null);
|
||||||
...data,
|
} else {
|
||||||
lastAnnouncedPrice: lastAnnouncedPrice,
|
resolve(row?.value || null);
|
||||||
};
|
}
|
||||||
|
});
|
||||||
fs.writeFileSync(solanaDataFile, JSON.stringify(dataToSave, null, 2), 'utf8');
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function readSolanaData() {
|
async function updateMessageId(messageId) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
db.run('INSERT OR REPLACE INTO bot_state (key, value) VALUES (?, ?)',
|
||||||
|
['priceMessageId', messageId],
|
||||||
|
err => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Error updating message ID:', err);
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updatePriceMessage(channel, currentPrice) {
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(solanaDataFile)) {
|
const changes = await calculateChanges(currentPrice);
|
||||||
const fileContent = fs.readFileSync(solanaDataFile, 'utf8');
|
const embed = await createPriceEmbed(currentPrice, changes);
|
||||||
const data = JSON.parse(fileContent);
|
let messageId = await getMessageId();
|
||||||
|
let success = false;
|
||||||
|
|
||||||
lastAnnouncedPrice = data.lastAnnouncedPrice || null;
|
if (messageId) {
|
||||||
return data;
|
try {
|
||||||
|
const message = await channel.messages.fetch(messageId);
|
||||||
|
await message.edit({ embeds: [embed] });
|
||||||
|
success = true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to edit existing message:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
try {
|
||||||
|
const message = await channel.send({ embeds: [embed] });
|
||||||
|
await updateMessageId(message.id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to send new message:', error);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||||
|
try {
|
||||||
|
const message = await channel.send({ embeds: [embed] });
|
||||||
|
await updateMessageId(message.id);
|
||||||
|
} catch (retryError) {
|
||||||
|
console.error('Failed to send message after retry:', retryError);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error reading Solana data:', error);
|
console.error('Error in updatePriceMessage:', error);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client.login(process.env.DISCORD_BOT_TOKEN);
|
async function checkPriceAndAnnounce() {
|
||||||
|
try {
|
||||||
|
const currentPrice = await fetchSolanaPrice();
|
||||||
|
if (!currentPrice) {
|
||||||
|
setTimeout(checkPriceAndAnnounce, PRICE_CHECK_INTERVAL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await savePriceData(currentPrice);
|
||||||
|
const lastAnnouncedPrice = await getLastAnnouncedPrice();
|
||||||
|
|
||||||
|
const priceChannel = await client.channels.fetch(process.env.SOLANA_PRICE_CHANNEL_ID);
|
||||||
|
await updatePriceMessage(priceChannel, currentPrice);
|
||||||
|
|
||||||
|
if (lastAnnouncedPrice && (parseFloat(currentPrice) - lastAnnouncedPrice >= PRICE_INCREASE_THRESHOLD)) {
|
||||||
|
const announcementsChannel = await client.channels.fetch(process.env.ANNOUNCEMENTS_CHANNEL_ID);
|
||||||
|
await announcementsChannel.send(
|
||||||
|
`@everyone Solana price has increased significantly! Current price: $${currentPrice} (Up $${(parseFloat(currentPrice) - lastAnnouncedPrice).toFixed(2)} from last announcement)`
|
||||||
|
);
|
||||||
|
await updateLastAnnouncedPrice(parseFloat(currentPrice));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in price check and announce cycle:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(checkPriceAndAnnounce, PRICE_CHECK_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupOldData() {
|
||||||
|
const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000);
|
||||||
|
db.run('DELETE FROM price_history WHERE timestamp < ?', [oneDayAgo], (err) => {
|
||||||
|
if (err) console.error('Error cleaning up old data:', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
db.on('error', (err) => {
|
||||||
|
console.error('Database error:', err);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.once('ready', () => {
|
||||||
|
console.log('Bot is online!');
|
||||||
|
checkPriceAndAnnounce();
|
||||||
|
setInterval(cleanupOldData, 6 * 60 * 60 * 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('error', error => {
|
||||||
|
console.error('Discord client error:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('shardError', error => {
|
||||||
|
console.error('Discord websocket error:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', error => {
|
||||||
|
console.error('Unhandled promise rejection:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login(process.env.DISCORD_BOT_TOKEN);
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,8 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.14.1",
|
"discord.js": "^14.16.3",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"node-fetch": "^3.3.2"
|
"node-fetch": "^3.3.2",
|
||||||
|
"sqlite3": "^5.1.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue