antizucc/index.js

134 lines
3.5 KiB
JavaScript

const discord = require("discord.js");
require("dotenv").config();
// for some reason, node.js's built-in fetch function doesn't work for this
// also node-fetch doesn't like being required
const fetch = (...args) => import("node-fetch").then(n => n.default(...args));
const client = new discord.Client({
intents: [
discord.GatewayIntentBits.Guilds,
discord.GatewayIntentBits.GuildMessages,
discord.GatewayIntentBits.MessageContent,
],
sweepers: {
messages: {
lifetime: 3600,
interval: 3600,
}
}
});
// grab data from an instagram url
async function fetchData(url) {
const res = await fetch(url, {
headers: {
'User-Agent': 'curl/8.1.0',
'Accept': '*/*'
},
credentials: "omit",
});
if(!res.ok) {
console.log("oops. fetching instagram link returned bad status", res.statusText);
return;
}
const text = await res.text();
// here's where the wacky stuff happens
// okay so instagram for some reason includes a full JSON-LD dump of
// the post in the html returned, in this script tag
// i just need to find the boundaries and parse the json
let index = text.indexOf('<script type="application/ld+json"');
if(index < 0) {
console.log("couldn't find json data in html");
return;
}
let json = text.substring(index);
json = json.replace(/^<script type="application\/ld\+json"( nonce="[^"]+")?>/, "");
console.log("Found JSON");
index = json.indexOf('}</script>');
if(index < 0) {
console.log("couldn't find end of json data in html");
return;
}
json = json.substring(0, index+1);
let data;
try {
data = JSON.parse(json);
} catch(err) {
console.log("couldn't parse json", err);
return;
}
return data;
}
client.on("messageCreate", async message => {
if(message.author.bot) {
return;
}
if(!/^https?:\/\/(www\.)?instagram\.com\/reel/.test(message.content)) {
return;
}
const url = message.content.split(" ")[0];
console.log("Fetching content for URL: " + url);
let data;
try {
data = await fetchData(url);
} catch(err) {
console.log("Error fetching, retrying:", err);
try {
data = await fetchData(url);
} catch(err) {
console.log("Error fetching URL: " + url);
console.log("Error:", err);
message.channel.send("Failed to fetch data for link");
return;
}
}
if(!data) {
console.log("data is empty");
message.channel.send("Link had no data, or something went wrong");
return;
}
const sendObj = {
embeds: [{
author: {
name: data?.author?.alternateName,
icon_url: data?.author?.image,
},
title: data?.author?.name,
description: data?.headline,
}],
files: (data.video || []).map(d => d.contentUrl)
};
const interval = setInterval(() => message.channel.sendTyping().catch(() => {}), 3000);
let success = true;
try {
console.log("posting...");
message.channel.sendTyping().catch(() => {});
await message.channel.send(sendObj);
} catch(err) {
console.log("Error posting to discord, attempting backup:", err);
sendObj.content = sendObj.files.join(" ");
delete sendObj.files;
try {
await message.channel.send(sendObj);
} catch(err) {
console.log("error posting backup", err);
success = false;
}
}
if(success) console.log("posted!");
clearInterval(interval);
});
client.login(process.env.TOKEN).then(() => console.log("Logged into Discord as", client.user.username + "#" + client.user.discriminator));