Skip to content

Instantly share code, notes, and snippets.

@alip-jmbd
Created December 12, 2025 01:47
Show Gist options
  • Select an option

  • Save alip-jmbd/46f682de822b01d90fc6f3c0cf4cc69f to your computer and use it in GitHub Desktop.

Select an option

Save alip-jmbd/46f682de822b01d90fc6f3c0cf4cc69f to your computer and use it in GitHub Desktop.
Scraper Anichin.cafe, search, detail, stream (embed), ongoing, completed
// install dulu
// npm i @elainaa/tls cheerio commander
import { ElainaTLS } from '@elainaa/tls'
import * as cheerio from 'cheerio'
import { program } from 'commander'
const client = new ElainaTLS()
const BASE_URL = 'https://anichin.cafe'
const fetchHTML = async (url) => {
try {
const response = await client.fetch(url, {
headers: {
'Referer': BASE_URL,
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}
})
if (response.status !== 200) {
throw new Error(`Status Code: ${response.status}`)
}
return cheerio.load(response.body)
} catch (error) {
console.log(JSON.stringify({ status: false, message: error.message }, null, 2))
process.exit(1)
}
}
const parseList = ($) => {
const results = []
$('.listupd .bs').each((i, el) => {
const title = $(el).find('.tt h2').text().trim()
const url = $(el).find('a').attr('href')
const image = $(el).find('img').attr('src')
const type = $(el).find('.typez').text().trim()
const status = $(el).find('.status').text().trim()
const episode = $(el).find('.epx').text().trim()
results.push({ title, url, image, type, status, episode })
})
return results
}
const search = async (query) => {
const url = `${BASE_URL}/?s=${encodeURIComponent(query)}`
const $ = await fetchHTML(url)
const data = parseList($)
console.log(JSON.stringify({ status: true, data }, null, 2))
}
const ongoing = async (page = 1) => {
const url = page == 1 ? `${BASE_URL}/ongoing/` : `${BASE_URL}/ongoing/page/${page}/`
const $ = await fetchHTML(url)
const data = parseList($)
console.log(JSON.stringify({ status: true, page: parseInt(page), data }, null, 2))
}
const completed = async (page = 1) => {
const url = page == 1 ? `${BASE_URL}/completed/` : `${BASE_URL}/completed/page/${page}/`
const $ = await fetchHTML(url)
const data = parseList($)
console.log(JSON.stringify({ status: true, page: parseInt(page), data }, null, 2))
}
const detail = async (url) => {
const $ = await fetchHTML(url)
const title = $('.entry-title').text().trim()
const alt_title = $('.alter').text().trim()
const image = $('.thumb img').attr('src')
const rating = $('.rating strong').text().replace('Rating', '').trim()
const synopsis = $('.entry-content[itemprop="description"]').text().trim()
const metadata = {}
$('.infox .spe span').each((i, el) => {
const key = $(el).find('b').text().replace(':', '').trim().toLowerCase().replace(/\s/g, '_')
const val = $(el).text().replace($(el).find('b').text(), '').trim()
if(key) metadata[key] = val
})
const genres = []
$('.genxed a').each((i, el) => genres.push($(el).text()))
const episodes = []
const episodeList = $('.eplister ul li')
episodeList.each((i, el) => {
const epNum = $(el).find('.epl-num').text().trim()
const epTitle = $(el).find('.epl-title').text().trim()
const epUrl = $(el).find('a').attr('href')
const date = $(el).find('.epl-date').text().trim()
episodes.push({
episode: epNum,
title: epTitle,
url: epUrl,
release_date: date
})
})
console.log(JSON.stringify({
status: true,
data: {
title,
alternative_title: alt_title,
image,
rating,
synopsis,
metadata,
genres,
episodes
}
}, null, 2))
}
const stream = async (url) => {
const $ = await fetchHTML(url)
const title = $('.entry-title').text().trim()
const seriesUrl = $('.ts-breadcrumb ol li:nth-child(2) a').attr('href')
const prevUrl = $('.naveps .nvs a[rel="prev"]').attr('href') || null
const nextUrl = $('.naveps .nvs a[rel="next"]').attr('href') || null
const streamServers = []
const defaultEmbed = $('#pembed iframe').attr('src')
if(defaultEmbed) {
streamServers.push({ name: 'Default', url: defaultEmbed })
}
$('select.mirror option').each((i, el) => {
const name = $(el).text().trim()
const val = $(el).val()
if (val) {
try {
const decoded = Buffer.from(val, 'base64').toString('utf-8')
const srcMatch = decoded.match(/src="([^"]+)"/)
if (srcMatch && srcMatch[1]) {
streamServers.push({ name, url: srcMatch[1] })
}
} catch (e) {}
}
})
const downloadLinks = []
$('.soraurlx').each((i, el) => {
const resolution = $(el).find('strong').text().trim()
const links = []
$(el).find('a').each((j, link) => {
links.push({
host: $(link).text().trim(),
url: $(link).attr('href')
})
})
downloadLinks.push({ resolution, links })
})
console.log(JSON.stringify({
status: true,
data: {
title,
series_url: seriesUrl,
navigation: { prev: prevUrl, next: nextUrl },
streams: streamServers,
downloads: downloadLinks
}
}, null, 2))
}
program
.name('anichin')
.description('CLI Data Scraper for Anichin.cafe')
.version('1.0.0')
program.command('search')
.argument('<keyword>', 'Search query')
.action(search)
program.command('ongoing')
.argument('[page]', 'Page number', 1)
.action(ongoing)
program.command('completed')
.argument('[page]', 'Page number', 1)
.action(completed)
program.command('detail')
.argument('<url>', 'Anime URL')
.action(detail)
program.command('stream')
.argument('<url>', 'Episode URL')
.action(stream)
program.parse()
@alip-jmbd
Copy link
Author

Filter nya malas imtu amja omkeh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment