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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@abstract_/exodusmeme

v1.2.8

Published

High-performance, extensible meme engine for Discord bots and Node.js.

Readme

ExodusMeme 🚀

Motor de memes de alto rendimiento para Node.js y Discord bots.
Optimizado para Discord, diseñado para velocidad y extensibilidad.

npm version npm downloads License: MIT TypeScript


🧠 ¿Qué es ExodusMeme?

ExodusMeme no es solo otro fetcher de Reddit. Es un motor completo de orquestación de memes con múltiples fuentes integradas. Ya sea que estés construyendo un bot de Discord, una herramienta de automatización de redes sociales, o simplemente necesites un flujo constante de memes, ExodusMeme proporciona una API robusta, type-safe y con caché.

✨ Características Principales

  • 🎯 Rendimiento Extremo: Capa de caché integrada (TTL) y throttling de peticiones
  • 🔌 Múltiples Fuentes: Sistema multi-API que combina want.cat, Reddit APIs y más fuentes integradas
  • 🌐 Arquitectura Pluggable: Añade fácilmente fuentes personalizadas de Reddit, Twitter o tus propias APIs
  • 🛡️ Filtros Inteligentes: Detección NSFW avanzada, umbrales de upvotes y filtrado por tipo de media
  • 🤖 Nativo de Discord: Soporte de primera clase para embeds de Discord con truncamiento y formato automático
  • 🧬 Type Safety: Escrito desde cero en TypeScript para mejor experiencia de desarrollo
  • 🚀 Anti-Duplicados: Sistema de deduplicación con Set para evitar memes repetidos
  • Caché Inteligente: Caché en memoria con duración de 3-5 minutos para máxima frescura

📦 Instalación

npm install @abstract_/exodusmeme

🚀 Inicio Rápido

Nota: ExodusMeme usa por defecto la fuente multiapi que combina múltiples APIs para mayor variedad y disponibilidad.

1. Fetch Simple (CommonJS)

const { memeForge } = require('@abstract_/exodusmeme');

async function getMemes() {
    const memes = await memeForge.fetch({
        limit: 5,
        minUpvotes: 500,
        nsfw: false
    });
    
    console.log(memes);
}

getMemes();

2. Fetch Simple (ES Modules)

import { memeForge } from '@abstract_/exodusmeme';

const memes = await memeForge.fetch({
    limit: 5,
    minUpvotes: 500,
    nsfw: false
});

console.log(memes);

3. Bot de Discord con discord.js v14 (CommonJS)

const { Client, GatewayIntentBits } = require('discord.js');
const { memeForge } = require('@abstract_/exodusmeme');

const client = new Client({
    intents: [GatewayIntentBits.Guilds]
});

client.on('interactionCreate', async (interaction) => {
    if (!interaction.isChatInputCommand()) return;
    
    if (interaction.commandName === 'meme') {
        await interaction.deferReply();
        
        const memes = await memeForge.fetch({
            limit: 1,
            minUpvotes: 500,
            nsfw: false,
            mediaType: 'image'
        });
        
        if (memes.length === 0) {
            await interaction.editReply('No se encontraron memes 😢');
            return;
        }
        
        const meme = memes[0];
        
        const embed = {
            title: meme.title,
            url: meme.sourceUrl,
            image: { url: meme.url },
            color: 0xff4500,
            footer: {
                text: `👍 ${meme.upvotes.toLocaleString()} • r/${meme.subreddit}`
            }
        };
        
        await interaction.editReply({ embeds: [embed] });
    }
});

client.login('YOUR_TOKEN');

4. Bot de Discord (ES Modules)

import { Client, GatewayIntentBits } from 'discord.js';
import { memeForge } from '@abstract_/exodusmeme';

const client = new Client({
    intents: [GatewayIntentBits.Guilds]
});

client.on('interactionCreate', async (interaction) => {
    if (!interaction.isChatInputCommand()) return;
    
    if (interaction.commandName === 'meme') {
        await interaction.deferReply();
        
        const memes = await memeForge.fetch({
            limit: 1,
            minUpvotes: 500,
            nsfw: false,
            mediaType: 'image'
        });
        
        if (memes.length === 0) {
            await interaction.editReply('No se encontraron memes 😢');
            return;
        }
        
        const meme = memes[0];
        
        const embed = {
            title: meme.title,
            url: meme.sourceUrl,
            image: { url: meme.url },
            color: 0xff4500,
            footer: {
                text: `👍 ${meme.upvotes.toLocaleString()} • r/${meme.subreddit}`
            }
        };
        
        await interaction.editReply({ embeds: [embed] });
    }
});

client.login('YOUR_TOKEN');

5. Bot con Comandos de Prefijo (CommonJS)

const { Client, GatewayIntentBits } = require('discord.js');
const { memeForge } = require('@abstract_/exodusmeme');

const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent
    ]
});

const prefix = '!';

client.on('messageCreate', async (message) => {
    if (message.author.bot || !message.content.startsWith(prefix)) return;
    
    const args = message.content.slice(prefix.length).trim().split(/ +/);
    const command = args.shift().toLowerCase();
    
    if (command === 'meme') {
        const memes = await memeForge.fetch({
            limit: 1,
            minUpvotes: 500,
            nsfw: false,
            mediaType: 'image'
        });
        
        if (memes.length === 0) {
            await message.reply('No se encontraron memes 😢');
            return;
        }
        
        const meme = memes[0];
        
        const embed = {
            title: meme.title,
            url: meme.sourceUrl,
            image: { url: meme.url },
            color: 0xff4500,
            footer: {
                text: `👍 ${meme.upvotes.toLocaleString()} • r/${meme.subreddit}`
            }
        };
        
        await message.reply({ embeds: [embed] });
    }
});

client.login('YOUR_TOKEN');

6. Subreddits Personalizados

const { memeForge } = require('@abstract_/exodusmeme');

const memes = await memeForge.fetch({
    subreddits: ['MAAU', 'yo_elvr', 'LatinoPeopleTwitter'],
    limit: 10,
    minUpvotes: 1000
});

⚙️ Configuración Avanzada

| Opción | Tipo | Default | Descripción | | --- | --- | --- | --- | | source | string | 'multiapi' | Motor de fuente: multiapi, reddit, memeapi o personalizado | | subreddits | string[] | - | Lista de subreddits (solo aplica para fuente reddit) | | limit | number | 1 | Número de memes a obtener | | nsfw | boolean | true | ¿Incluir contenido NSFW? | | minUpvotes| number | 0 | Filtro de upvotes mínimos | | mediaType | string | 'any' | image, gif, video, o any | | format | string | 'json' | json o discord-embed | | cache | boolean | true | Activar/Desactivar caché en memoria |

📡 Fuentes Disponibles

MultiAPI (Default) - Combina múltiples APIs para máxima variedad:

  • want.cat API
  • Reddit MAAU
  • Reddit yo_elvr
  • Reddit LatinoPeopleTwitter

MemeAPI - Fuente alternativa usando meme-api.com:

const memes = await memeForge.fetch({
    source: 'memeapi',
    limit: 10
});

Reddit - Acceso directo a Reddit JSON:

const memes = await memeForge.fetch({
    source: 'reddit',
    subreddits: ['memes', 'dankmemes'],
    limit: 10
});

🔄 Características Avanzadas

Sistema Anti-Duplicados

ExodusMeme implementa un sistema de deduplicación que mantiene un Set de los últimos 150-300 IDs de memes vistos, dependiendo de la fuente. Esto garantiza que no veas el mismo meme repetidas veces:

const memes = await memeForge.fetch({ limit: 20 });

Caché Inteligente

Cada fuente implementa su propio sistema de caché con diferentes duraciones:

  • MultiAPI: 3 minutos (180 segundos)
  • MemeAPI: 5 minutos (300 segundos)
  • Reddit: 2 minutos (120 segundos)

Esto asegura un balance entre frescura de contenido y eficiencia:

const memes = await memeForge.fetch({ 
    limit: 10,
    cache: true
});

Rate Limiting

Las fuentes implementan throttling automático para evitar sobrecarga de las APIs:

const rateLimiter = new RateLimiter(0.5);
await rateLimiter.throttle('multiapi');

🆘 Soporte y Comunidad

¿Tienes problemas? ¡Estamos aquí para ayudar!

  • 🐛 ¿Encontraste un bug? Abre un Issue
  • 💬 ¿Necesitas ayuda? Únete a nuestro Discord
  • 🛠️ ¿Error en la docs? ¡Los pull requests son bienvenidos!

📜 Licencia

MIT © NotAvalible111