npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ifunnynode

v3.0.10

Published

Api wrapper for IFunny.mobi in Node.js

Downloads

6

Readme

iFunnyNode 3.0.7

This is an iFunny API Wrapper written in ES6 Node JS.
This project is nearly complete, with only a few features not implemented.
Chats have been implemented!
I couldn't have done it without the amazing help from my good friend Tobi/Pain so big thanks to him for everything having to do with Chats.\

  • This wrapper was written from scratch, taking inspiration from discord.py, discord.js, ifunnyapi, and iFunny.js. iFunny.js played a huge role in developing this client, so the author of that was listed as a contributor.

How do I use the module?

To install, type npm install ifunnynode in your terminal or sudo npm install ifunnynode if you're on linux

// ES6
import Client from "ifunnynode";
const client = new Client();

// Login event
client.on("login", (logged_in) => {
	console.log(logged_in ? "Made login request" : "Used stored bearer");
	client.chats.connect();
});

client.chats.on("message", async (ctx) => {
	console.log(ctx.message.content);
});

client.login({ token: "token" });
// CommonJS
const Client = require("ifunnynode").default;
const client = new Client();

// Login event
client.on("login", (logged_in) => {
	console.log(logged_in ? "Made login request" : "Used stored bearer");
	client.chats.connect();
});

// Message event
client.chats.on("message", async (ctx) => {
	console.log(ctx.message.content);
});

client.login({ token: "token" });
// Typescript
import Client from "ifunnynode";
import type { Context } from "ifunnynode"; // Should have full TypeScript support, excluding events (will be worked on)
const client: Client = new Client();

// Login event
client.on("login", (logged_in: boolean) => {
	console.log(logged_in ? "Made login request" : "Used stored bearer");
	client.chats.connect();
});

// Message event
client.chats.on("message", async (ctx: Context) => {
	console.log(ctx.message.content);
});

client.login({ token: "token" });

Logging in

Logging in for the first time isn't as simple as it used to be due to iFunny updating their API
iFunny will sometimes return a captcha error, so you'll need to solve them

  1. Create a try block with your login method being called there
  2. Add a catch block and check for err.captcha_url
    1. Open the captcha url in a browser and solve it
    2. Attempt to login in again with the same credentials
  3. You're done!

How do I get a basic token?

// CommonJS
const Client = require("ifunnynode").default;
const client = new Client();
console.log(client.basic_token); // Store this yourself
// ES6 or TypeScript
import Client from "ifunnynode";
const client = new Client();
console.log(client.basic_token); // Store this yourself
import Client from "ifunnynode";

// Get your credentials
const EMAIL = process.env.IFUNNY_NODE_EMAIL;
const PASSWORD = process.env.IFUNNY_NODE_PASSWORD;
const BASIC_TOKEN = process.env.IFUNNY_BASIC_TOKEN ?? new Client().basic_token; // Generates a new basic token.

/**
 * The wrapper doesn't store the basic token,
 * which needs to be reused to login,
 * so you'll wanna store this before attempting a login.
 * You can avoid having to store the basic token if you use a service like 2captcha to solve captchas programatically.
 */
process.env.IFUNNY_BASIC_TOKEN = BASIC_TOKEN;

// It's a good idea to use the same basic token for captcha requests, but you aren't required to pass in a basic token.
const client = new Client({
	basic: BASIC_TOKEN,
});

// Login event emits a boolean if it had to generate a new bearer token.
client.on("login", async (new_bearer) => {
	console.log(`new bearer ${new_bearer}`);
});

(async () => {
	try {
		// Since we don't have a bearer token stored, we need to pass an email and a password
		await client.login({
			email: EMAIL,
			password: PASSWORD,
		});
	} catch (err) {
		// check if error was CaptchaError
		if (err.captcha_url) {
			// Open this url in the browser and solve it, then make the request again, using the same basic token
			console.log(err.captcha_url);
		} else {
			// NOT a CaptchaError
			throw err;
		}
	}
})();

Basic command example

// Import the Client from npm
import Client from "ifunnynode";

// Construct the client
const client = new Client({
	token: "bearer",
	basic: "basic_token",
});

// Since we already have a bearer, we don't need to pass any arguments
client.login();

// On Client.login, execute a callback so that we know the client is valid
client.on("login", async () => {
	// Log info to the console (optional)
	console.log(`Client logged in as ${await client.nick} (${client.id_sync})`);

	// Connect to chats
	client.chats.connect();
});

/**
 * Gets the stats of the user and returns them as a string
 * @param {User} user
 */
async function stats(user) {
	let str = "";
	str += `Total Posts: ${await user.post_count}\n`;
	str += `Features: ${await user.feature_count}\n`;
	str += `Total Smiles: ${await user.smile_count}\n`;
	str += `Total Subscribers: ${await user.subscriber_count}\n`;
	str += `Total Subscriptions: ${await user.subscription_count}`;
	return str;
}

client.chats.on(
	"message",
	/** @param {Context} ctx */
	async (ctx) => {
		// Ignore self
		if (ctx.message.author.is_me) return; // Bot will not respond to itself

		//if (!ctx.message.author.is_me) return; // Bot will ONLY respond to itself

		// This isn't how you *should* handle it, but how you *can* handle it.
		// Command with name "mystats" that sends the users profile stats
		if (ctx.message.content === "!mystats") {
			await ctx.channel.send(await stats(ctx.message.author)); // Send the user their stats
		}
	}
);