A 39-line Node.js bot that scrapes iFunny video links and auto-embeds them in Discord.
Links from the social media site ifunny.co don't auto-embed within Discord. When sharing links to videos it is inconvenient to be redirected to your browser on PC or be forced into a different app on mobile just to view them.
Just because ifunny.co doesn't have embed handling for link sharing doesn't stop us from handling the data ourselves from their CDN. Hidden inside the data returned from the HTTPS request to ifunny.co is an .mp4 file we can sniff and scrape out.
iFunny doesn't give us any APIs to work with to efficiently retrieve data, so we have to work with the source HTML given through the HTTPS request. Let's take a look at the <video> tag to see what hints we can find.
This looks like visual garbage. Our mp4 is inside the video tag though. The HTML data can be treated as a giant string, and we can search for .mp4. This yields ~5 results per page, some of which are bogus.
data-src attribute (possibly used for lazy loading) is the only occurrence on the page and contains our proper data. This allows us to do only 1 search, and no conditional logic.
Since we know what we're looking for we can use String.search() to find our substring.
let index = data.search("data-src=");
Once we have the starting index, we walk forward character by character until we hit the closing quote, building the URL as we go:
// data-src="https://img.ifunny.co/videos/ec20...e46b664c3499d820_1.mp4"
for (index += 10; index < data.length; index++) {
if (data[index] != "\"")
tempstr += data[index];
else
break;
}
DiscordJS makes this easy. We can pass our link data with the original message object to reply with our scraped link in the same channel.
message.channel.send("" + string);
const { Client, Intents } = require("discord.js");
const client = new Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES],
});
const request = require("request");
const ifunnyLink = "https://ifunny.co/video";
client.once("ready", () => {
console.log("Discord bot operational");
});
client.on("message", message => {
if (!message.content.startsWith(ifunnyLink) || message.author.bot) return;
queryAndSend("" + message.content, message);
});
client.login("Super Secret Key");
function queryAndSend(link, message) {
let tempstr = "";
request(
`` + link,
(err, response, body) => {
let data = body;
dataLength = data.length;
let index = data.search("data-src=");
for (let i = index + 10; i < data.length; i++) {
if (data[i] != "\"")
tempstr += data[i];
else
break;
}
sendMessage(tempstr, message);
}
);
}
function sendMessage(string, message) {
message.channel.send("" + string);
}