Files
daily-digest/index.ts
2026-07-23 13:06:41 +05:30

182 lines
3.4 KiB
TypeScript

import { $ } from "bun"
import dayjs from "dayjs"
import "dayjs/locale/es"
const TOPIC = "daily-digest"
const TOKEN = process.env.NTFY_TOKEN
if (!TOKEN) {
console.error("ntfy token not set")
process.exit(1)
}
const API =
"https://api.frankfurter.app/latest?from=USD&to=INR"
async function getUSD() {
const res = await fetch(API)
if (!res.ok) {
throw new Error(`Exchange API failed: ${res.status}`)
}
const data = await res.json()
const rate = data.rates.INR
if (typeof rate !== "number") {
throw new Error("Invalid exchange rate")
}
const helions = (rate / 100).toFixed(2)
return `**📈 Exchange Rate**
$1 = ₹${rate.toFixed(2)} = ⚙${helions}
`
}
async function getUsage() {
//
// CPU LOAD
//
const loadavg = await $`cat /proc/loadavg`.text()
const [load1] = loadavg.trim().split(" ")
//
// MEMORY
//
const memRaw = await $`free -b`.text()
const memLine = memRaw
.split("\n")
.find((line) => line.startsWith("Mem:"))
if (!memLine) {
throw new Error("Failed to parse memory info")
}
const [
,
totalMem,
usedMem,
] = memLine.trim().split(/\s+/)
//
// DISK
//
const diskRaw = await $`df -B1 /`.text()
const diskLine = diskRaw
.split("\n")[1]
if (!diskLine) {
throw new Error("Failed to parse disk info")
}
const [
,
totalDisk,
usedDisk,
] = diskLine.trim().split(/\s+/)
const temp = await $`vcgencmd measure_temp`.text()
const tempData = temp.split("=")[1].replace("'", "°")
//
// HELPERS
//
function formatBytesIEC(bytes: number) {
const units = ["B", "KiB", "MiB", "GiB", "TiB"]
let i = 0
let value = bytes
while (value >= 1024 && i < units.length - 1) {
value /= 1024
i++
}
return `${value.toFixed(1)} ${units[i]}`
}
//
// OUTPUT
//
return `**💾 Usage**
• **CPU:** ${load1}
• **Memory:** ${formatBytesIEC(Number(usedMem))} / ${formatBytesIEC(Number(totalMem))}
• **Disk:** ${formatBytesIEC(Number(usedDisk))} / ${formatBytesIEC(Number(totalDisk))}
• **Temperature:** ${tempData}
`
}
async function getWeather() {
const res = await fetch(`https://wttr.in/Bengaluru?format="%c%C| %f | %h | %m | %w | %p"`)
const data = await res.text()
const [weather, temp, humidity, moon, winds, preci] = data.replace(/\"/g, '').split("|")
return `**🌥️ Weather Report**
• **Weather:** ${weather}
• **Temperature:** ${temp}
• **Humidity:** ${humidity}
• **Moon Phase:** ${moon}
• **Winds:** ${winds}
• **Precipitation:** ${preci}
`
console.log(data)
}
async function main() {
const usd = await getUSD()
const usage = await getUsage()
const weather = await getWeather()
const message = `Good Morning, SilicoFlare!
Today is **${dayjs().format("dddd, DD MMMM YYYY")}**.
Hoy es **${dayjs().locale("es").format("dddd, D [de] MMMM [de] YYYY")}**.
${weather}
${usd}
${usage}
Have a great day!`
const ntfy = await fetch(
`https://ntfy.hy-pr.link/${TOPIC}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${TOKEN}`,
Title: `Daily Digest for ${dayjs().format("YYYY-MM-DD")}`,
Markdown: "yes",
Tags: "calendar"
},
body: message,
},
)
if (!ntfy.ok) {
throw new Error(`ntfy failed: ${ntfy.status}`)
}
console.log("Notification sent at " + dayjs().format("YYYY-MM-dd HH:mm:ss"))
}
main().catch((err) => {
console.error(err)
process.exit(1)
})