107 lines
2.7 KiB
Text
107 lines
2.7 KiB
Text
import { Client, GatewayIntentBits } from "discord.js";
|
|
import crypto from "crypto";
|
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
|
|
/* ================= CONFIG ================= */
|
|
const REFRESH_MS = Number(process.env.REFRESH_MS ?? 15_000);
|
|
const STATE_FILE = "./state.json";
|
|
|
|
/* ================= DISCORD ================= */
|
|
const client = new Client({
|
|
intents: [GatewayIntentBits.Guilds],
|
|
});
|
|
|
|
/* ================= STATE ================= */
|
|
let messageId = null;
|
|
let lastSignature = null;
|
|
|
|
if (existsSync(STATE_FILE)) {
|
|
try {
|
|
const state = JSON.parse(readFileSync(STATE_FILE, "utf8"));
|
|
messageId = state.messageId ?? null;
|
|
lastSignature = state.lastSignature ?? null;
|
|
} catch {}
|
|
}
|
|
|
|
function saveState() {
|
|
writeFileSync(
|
|
STATE_FILE,
|
|
JSON.stringify({ messageId, lastSignature }, null, 2)
|
|
);
|
|
}
|
|
|
|
/* ================= NAVIDROME AUTH ================= */
|
|
function navidromeAuth() {
|
|
const salt = crypto.randomBytes(6).toString("hex");
|
|
const token = crypto
|
|
.createHash("md5")
|
|
.update(process.env.NAVIDROME_PASS + salt)
|
|
.digest("hex");
|
|
|
|
return { salt, token };
|
|
}
|
|
|
|
function nowPlayingUrl() {
|
|
const { salt, token } = navidromeAuth();
|
|
return `${process.env.NAVIDROME_URL}/rest/getNowPlaying` +
|
|
`?u=${process.env.NAVIDROME_USER}` +
|
|
`&t=${token}&s=${salt}&f=json&v=1.16.1&c=discord-bot`;
|
|
}
|
|
|
|
function coverFetchUrl(id) {
|
|
const { salt, token } = navidromeAuth();
|
|
return `${process.env.NAVIDROME_URL}/rest/getCoverArt` +
|
|
`?u=${process.env.NAVIDROME_USER}` +
|
|
`&t=${token}&s=${salt}&v=1.16.1&c=discord-bot` +
|
|
`&id=${id}&size=96`;
|
|
}
|
|
|
|
/* ================= UTIL ================= */
|
|
function colorFromString(str) {
|
|
let hash = 0;
|
|
for (const c of str) hash = (hash << 5) - hash + c.charCodeAt(0);
|
|
return Math.abs(hash) % 0xffffff;
|
|
}
|
|
|
|
function signature(entries) {
|
|
return entries
|
|
.map(e => `${e.username}:${e.id}:${e.minutesAgo ?? 0}`)
|
|
.join("|");
|
|
}
|
|
|
|
/* ================= NAVIDROME ================= */
|
|
async function getNowPlaying() {
|
|
const res = await fetch(nowPlayingUrl());
|
|
if (!res.ok) throw new Error("Failed to fetch now playing");
|
|
|
|
const json = await res.json();
|
|
return json["subsonic-response"].nowPlaying?.entry ?? [];
|
|
}
|
|
|
|
/* ================= MESSAGE BUILD ================= */
|
|
async function buildMessage(entries) {
|
|
if (!entries.length) {
|
|
return {
|
|
embeds: [{
|
|
title: "Nothing playing",
|
|
description: "No active listeners",
|
|
color: 0x808080,
|
|
}],
|
|
files: [],
|
|
};
|
|
}
|
|
|
|
const embeds = [];
|
|
const files = [];
|
|
|
|
for (let i = 0; i < e
|
|
DISCORD_TOKEN="no.no"
|
|
LASTFM_API_KEY=no
|
|
|
|
NAVIDROME_URL=https://no.no.no
|
|
NAVIDROME_USER="no"
|
|
NAVIDROME_PASS="no"
|
|
|
|
|
|
SPOTIFY_CLIENT_ID="no"
|
|
SPOTIFY_CLIENT_SECRET="no"
|