qrtzcode
HomeDocsAPILeaderboardChangelog
Contribute
Docs

qrtzcode

Kumpulan gist & snippet pribadi — anime, AI tools, scraper, dan randomness.

Navigate

HomeDocsAPI Reference

Links

© 2026 qrtz. All snippets welcome.

ESC

Navigate

Links

Anime

meownime

meow:3.

Creator

qrtz

Language

javascript

Views

26

Copies

6

Base

https://meownime.ltd

Updated

09 Agu 2026

#anime

Code

266
meownime.js
const axios = require('axios');
const cheerio = require('cheerio');
const https = require('https');

const BASE_URL = 'https://meownime.ltd';

const USER_AGENTS = [
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0',
  'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0',
];

function getRandomUA() {
  return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
}

function getRandomIP() {
  return `${Math.floor(Math.random()*256)}.${Math.floor(Math.random()*256)}.${Math.floor(Math.random()*256)}.${Math.floor(Math.random()*256)}`;
}

function buildHeaders() {
  const ua = getRandomUA();
  const isChrome = ua.includes('Chrome');
  const headers = {
    'User-Agent': ua,
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
    'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'none',
    'Sec-Fetch-User': '?1',
    'Cache-Control': 'max-age=0',
    'X-Forwarded-For': getRandomIP(),
    'Client-IP': getRandomIP(),
  };
  if (isChrome) {
    headers['Sec-Ch-Ua'] = '"Google Chrome";v="120", "Not_A Brand";v="99"';
    headers['Sec-Ch-Ua-Mobile'] = '?0';
    headers['Sec-Ch-Ua-Platform'] = '"Windows"';
  }
  return headers;
}

const agent = new https.Agent({
  rejectUnauthorized: false,
  keepAlive: true,
});

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function fetchHTML(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await axios.get(url, {
        headers: buildHeaders(),
        httpsAgent: agent,
        timeout: 30000,
        maxRedirects: 5,
        decompress: true,
      });
      await sleep(600 + Math.random() * 800);
      return response.data;
    } catch (e) {
      if (i === retries - 1) throw e;
      await sleep(1500 * (i + 1) + Math.random() * 1000);
    }
  }
}

function cleanText(text) {
  return text?.replace(/\s+/g, ' ').trim() || '';
}

function extractFromClass(classes, prefix) {
  const regex = new RegExp(`${prefix}-([a-zA-Z0-9-]+)`, 'g');
  const matches = classes?.match(regex) || [];
  return matches.map(m => m.replace(`${prefix}-`, ''));
}

function extractSlug(input) {
  if (input?.startsWith('http')) {
    const urlObj = new URL(input);
    const pathParts = urlObj.pathname.split('/').filter(p => p);
    return pathParts[pathParts.length - 1] || pathParts[0];
  }
  return input;
}

function buildListUrl(type, page, order) {
  const pathMap = {
    home: '/',
    ongoing: '/status/ongoing/',
    completed: '/status/completed/',
    movie: '/type/movie/',
  };
  let path = pathMap[type] || `/type/${type}/`;
  if (page && page > 1 && type !== 'home') {
    path = path.replace(/\/$/, '') + `/page/${page}/`;
  }
  const params = new URLSearchParams();
  if (order) params.set('orderby', order);
  const query = params.toString();
  return BASE_URL + path + (query ? '?' + query : '');
}

function parseListItems(html) {
  const $ = cheerio.load(html);
  const items = [];
  $('article.meownime.post, article.post').each(function() {
    const $el = $(this);
    const classes = $el.attr('class') || '';
    const id = $el.attr('id') || '';
    const postId = id.replace('post-', '');
    const $thumb = $el.find('.featured-thumb.grid-img');
    const $link = $thumb.find('a');
    const $img = $thumb.find('img');
    const $title = $el.find('.entry-title.title-font a');
    const $postedon = $el.find('.postedon');
    const title = cleanText($title.text());
    const url = $link.attr('href') || '';
    const thumbnail = $img.attr('src') || '';
    const ratingText = cleanText($postedon.text()).replace('★', '').trim();
    const rating = parseFloat(ratingText) || 0;
    const genres = extractFromClass(classes, 'genre');
    const studios = extractFromClass(classes, 'studio');
    const season = extractFromClass(classes, 'season')[0] || '';
    const status = extractFromClass(classes, 'status')[0] || '';
    const type = extractFromClass(classes, 'type')[0] || '';
    if (title || url) {
      items.push({
        id: postId,
        title,
        url: url.startsWith('http') ? url : BASE_URL + url,
        thumbnail,
        rating,
        genres,
        studios,
        season,
        status,
        type,
      });
    }
  });
  return items;
}

function parsePagination(html) {
  const $ = cheerio.load(html);
  const pageNumbers = [];
  $('.paginations .nav-links .page-numbers, .paginations .page-numbers').each(function() {
    const text = $(this).text().trim();
    if (text && !isNaN(text) && text !== '...') {
      const num = parseInt(text);
      if (!pageNumbers.includes(num)) pageNumbers.push(num);
    }
  });
  if (pageNumbers.length > 0) {
    const maxPage = Math.max(...pageNumbers);
    const result = [];
    for (let i = 1; i <= maxPage; i++) {
      result.push({ page: i, url: null });
    }
    return result;
  }
  const nextLink = $('.paginations .next.page-numbers').attr('href');
  if (nextLink) {
    const match = nextLink.match(/page\/(\d+)/);
    if (match) {
      const currentPage = parseInt(match[1]) - 1 || 1;
      return [{ page: currentPage, url: null }, { page: currentPage + 1, url: nextLink }];
    }
  }
  return [{ page: 1, url: null }];
}

async function scrapeList(type = 'home', page = 1, order = '') {
  if (type === 'home' && page > 1) {
    return { items: [], totalPages: 1, currentPage: page };
  }
  const url = buildListUrl(type, page, order);
  const html = await fetchHTML(url);
  const items = parseListItems(html);
  const pages = parsePagination(html);
  let totalPages = pages.length > 0 ? Math.max(...pages.map(p => p.page)) : 1;
  if (totalPages < page) totalPages = page;
  return { items, totalPages, currentPage: page };
}

async function scrapeGenre() {
  const html = await fetchHTML(BASE_URL + '/genre/');
  const $ = cheerio.load(html);
  const genres = [];
  $('.meow-genres ul li a').each(function() {
    const $el = $(this);
    const name = cleanText($el.text());
    const url = $el.attr('href') || '';
    genres.push({
      name,
      url: url.startsWith('http') ? url : BASE_URL + url,
    });
  });
  return genres;
}

async function scrapeJadwal() {
  const html = await fetchHTML(BASE_URL + '/jadwal/');
  const $ = cheerio.load(html);
  const schedule = {};
  $('aside.meow-list.meow-archive').each(function() {
    const $el = $(this);
    const day = cleanText($el.find('h1.letter').text());
    const items = [];
    $el.find('.penzbar .jdlbar ul li a.nyaalist').each(function() {
      const $a = $(this);
      const title = cleanText($a.text());
      const url = $a.attr('href') || '';
      const rel = $a.attr('rel') || '';
      items.push({
        title,
        url: url.startsWith('http') ? url : BASE_URL + url,
        id: rel,
      });
    });
    if (day && items.length > 0) {
      schedule[day] = items;
    }
  });
  return schedule;
}

async function scrapeGenreDetail(genre, page = 1) {
  let url = page > 1 ? `/genre/${genre}/page/${page}/` : `/genre/${genre}/`;
  let html = await fetchHTML(BASE_URL + url);
  if (html.includes('Page not found') || html.includes('nothing was found')) {
    url = page > 1 ? `/genre/${genre}/page/1/` : `/genre/${genre}/`;
    html = await fetchHTML(BASE_URL + url);
  }
  const items = parseListItems(html);
  const pages = parsePagination(html);
  let totalPages = pages.length > 0 ? Math.max(...pages.map(p => p.page)) : 1;
  if (totalPages < page) totalPages = page;
  return { items, totalPages, currentPage: page };
}

async function scrapeSearch(query, page = 1) {
  const url = page > 1 ? `/search/${encodeURIComponent(query)}/page/${page}/` : `/search/${encodeURIComponent(query)}/`;
  const html = await fetchHTML(BASE_URL + url);
  const items = parseListItems(html);
  const pages = parsePagination(html);
  let totalPages = pages.length > 0 ? Math.max(...pages.map(p => p.page)) : 1;
  if (totalPages < page) totalPages = page;
  return { items, totalPages, currentPage: page };
}

async function scrapeDetail(slugOrUrl) {
  const slug = extractSlug(slugOrUrl);
  const url = `/${slug}/`;
  const html = await fetchHTML(BASE_URL + url);
  const $ = cheerio.load(html);

  const title = cleanText($('.entry-title').text());
  const thumbnail = $('.single-featured').attr('src') || $('.featured-thumb img').attr('src') || '';

  let sinopsis = '';
  const sinopsisEl = $('.entry-content .mb-33 p, .entry-content p');
  sinopsisEl.each(function() {
    const text = cleanText($(this).text());
    if (text.length > 50) {
      sinopsis = text;
      return false;
    }
  });

  const genres = [];
  $('li.Genrex, .genre-tag a, .genres a').each(function() {
    const text = cleanText($(this).text());
    if (text) {
      const parts = text.split(',').map(s => cleanText(s));
      parts.forEach(p => {
        if (p && !genres.includes(p)) genres.push(p);
      });
    }
  });
  if (genres.length === 0) {
    const articleClasses = $('article.post').attr('class') || '';
    const genreClasses = extractFromClass(articleClasses, 'genre');
    genreClasses.forEach(g => {
      if (g && !genres.includes(g)) genres.push(g);
    });
  }

  const episodes = [];
  $('table.table-hover').each(function() {
    const $table = $(this);
    const rows = $table.find('tr');
    if (rows.length >= 2) {
      const titleRow = rows.eq(0);
      const linkRow = rows.eq(1);
      const resolution = cleanText(titleRow.text());
      const links = [];
      linkRow.find('a').each(function() {
        const href = $(this).attr('href') || '';
        const label = cleanText($(this).text());
        if (href && href.startsWith('http')) {
          links.push({ label, url: href });
        }
      });
      if (resolution && links.length > 0) {
        episodes.push({
          number: resolution,
          date: '',
          url: links[0].url,
          allLinks: links,
        });
      }
    }
  });

  if (episodes.length === 0) {
    $('.chapter-list .chapter-link, .eps-list a, .download-list a, .list-episode a').each(function() {
      const $el = $(this);
      const number = cleanText($el.find('.chapter-number').text()) || cleanText($el.find('.eps-number').text()) || cleanText($el.text());
      const date = cleanText($el.find('.chapter-date').text()) || '';
      const link = $el.attr('href') || '';
      if (link && link.startsWith('http')) {
        episodes.push({
          number: number || 'Link',
          date: date || '',
          url: link,
        });
      }
    });
  }

  return { title, thumbnail, sinopsis, genres, episodes };
}

function formatOutput(data, halaman = 'list', page = 1, totalPages = 1) {
  let halamanDisplay = halaman;
  if (halaman.startsWith('list-')) {
    halamanDisplay = halaman.substring(5);
  }
  return {
    creator: 'rynaqrtz',
    halaman: halamanDisplay,
    page,
    totalPages,
    totalItems: Array.isArray(data) ? data.length : (typeof data === 'object' ? Object.keys(data).length : 0),
    data,
  };
}

async function main() {
  const args = process.argv.slice(2);
  if (args.length === 0) {
    console.log(JSON.stringify({
      creator: 'rynaqrtz',
      error: 'Perintah diperlukan',
      usage: {
        list: 'node meownime.js list [--type home|ongoing|completed|movie] [--page 1] [--order a-z|newest|oldest|most_viewed]',
        genre: 'node meownime.js genre',
        jadwal: 'node meownime.js jadwal',
        search: 'node meownime.js search <query> [--page 1]',
        detail: 'node meownime.js detail <slug|url>',
      },
      example: {
        list: 'node meownime.js list --type ongoing --page 1 --order a-z',
        genre: 'node meownime.js genre',
        jadwal: 'node meownime.js jadwal',
        search: 'node meownime.js search haibara --page 1',
        detail: 'node meownime.js detail kimi-no-na-wa-sub-indo',
        detailUrl: 'node meownime.js detail https://meownime.ltd/kimi-no-na-wa-sub-indo/',
      }
    }, null, 2));
    return;
  }

  const command = args[0];

  try {
    let result, output;

    if (command === 'list') {
      let type = 'home';
      let page = 1;
      let order = '';
      for (let i = 1; i < args.length; i++) {
        if (args[i] === '--type' && args[i + 1]) {
          type = args[i + 1];
          i++;
        } else if (args[i] === '--page' && args[i + 1]) {
          page = parseInt(args[i + 1]) || 1;
          i++;
        } else if (args[i] === '--order' && args[i + 1]) {
          order = args[i + 1];
          i++;
        }
      }
      const data = await scrapeList(type, page, order);
      output = formatOutput(data.items, `list-${type}`, data.currentPage, data.totalPages);
    } else if (command === 'genre') {
      const data = await scrapeGenre();
      output = formatOutput(data, 'genre', 1, 1);
    } else if (command === 'jadwal') {
      const data = await scrapeJadwal();
      output = formatOutput(data, 'jadwal', 1, 1);
    } else if (command === 'genre-detail') {
      const genre = args[1];
      if (!genre) {
        console.log(JSON.stringify({ creator: 'rynaqrtz', error: 'Genre slug diperlukan' }, null, 2));
        return;
      }
      let page = 1;
      for (let i = 2; i < args.length; i++) {
        if (args[i] === '--page' && args[i + 1]) {
          page = parseInt(args[i + 1]) || 1;
          i++;
        }
      }
      const data = await scrapeGenreDetail(genre, page);
      output = formatOutput(data.items, `genre-${genre}`, data.currentPage, data.totalPages);
    } else if (command === 'search') {
      const query = args.slice(1).find(a => !a.startsWith('--')) || '';
      if (!query) {
        console.log(JSON.stringify({ creator: 'rynaqrtz', error: 'Query pencarian diperlukan' }, null, 2));
        return;
      }
      let page = 1;
      for (let i = 1; i < args.length; i++) {
        if (args[i] === '--page' && args[i + 1]) {
          page = parseInt(args[i + 1]) || 1;
          i++;
        }
      }
      const data = await scrapeSearch(query, page);
      output = formatOutput(data.items, 'search', data.currentPage, data.totalPages);
    } else if (command === 'detail') {
      const input = args[1];
      if (!input) {
        console.log(JSON.stringify({ creator: 'rynaqrtz', error: 'Slug atau URL diperlukan' }, null, 2));
        return;
      }
      const data = await scrapeDetail(input);
      output = formatOutput(data, 'detail', 1, 1);
    } else {
      console.log(JSON.stringify({
        creator: 'rynaqrtz',
        error: `Perintah tidak dikenal: ${command}`,
        available: ['list', 'genre', 'genre-detail', 'jadwal', 'search', 'detail']
      }, null, 2));
      return;
    }

    console.log(JSON.stringify(output, null, 2));
  } catch (err) {
    console.log(JSON.stringify({
      creator: 'rynaqrtz',
      error: err.message,
      stack: process.env.DEBUG ? err.stack : undefined,
    }, null, 2));
  }
}

if (require.main === module) {
  main();
}

module.exports = {
  fetchHTML,
  parseListItems,
  parsePagination,
  scrapeList,
  scrapeGenre,
  scrapeGenreDetail,
  scrapeJadwal,
  scrapeSearch,
  scrapeDetail,
  cleanText,
  extractFromClass,
  extractSlug,
  buildListUrl,
  formatOutput,
};

Rating

2.0(1)

Gimana snippet ini menurutmu?

</> Embed

Embed ke website / blog

<iframe src="https://qrtzcode.vercel.app/api/embed/anime/meownime" style="width:100%;height:400px;border:none;border-radius:12px;"></iframe>

Related Snippets

anoboy

semoga bermanfaat^^.

48
17

nimegami

Semoga bermanfaat^^.

46
14

Nonton Anime

yh.

29
10