gtw.
Note
gtw.
qrtz
javascript
19
0
https://movieku.rest
24 Jun 2026
Code
const axios = require('axios');
const { load } = require('cheerio');
const BASE = 'https://movieku.rest';
const UAS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/124.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/123.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/17.4 Safari/605.1.15',
'Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0',
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 Version/17.4 Mobile/15E148 Safari/604.1',
];
let uaIdx = 0;
function ua() { return UAS[uaIdx++ % UAS.length]; }
const api = axios.create({ timeout: 15000, headers: { 'Accept': 'text/html,application/xhtml+xml', 'Accept-Language': 'id-ID,id;q=0.9' } });
async function fetch(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const res = await api.get(url, { headers: { 'User-Agent': ua() } });
return res.data;
} catch (e) {
if (i === retries - 1) throw e;
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
}
}
}
function parseArticles(html) {
const $ = load(html);
const items = [];
$('article').each((i, article) => {
const a = $(article).find('a[href]').first();
if (!a) return;
const href = a.attr('href');
if (!href || (!href.includes('/series/') && !href.includes('/movie/'))) return;
const title = $(article).find('.entry-title').first().text().trim() || a.text().trim();
const img = $(article).find('img').first().attr('src') || '';
items.push({ title, link: new URL(href, BASE).href, image: img || undefined });
});
return items;
}
function parseSeriesDetail(html) {
const $ = load(html);
const title = $('title').text().replace(/ - Movieku.*/, '').trim();
const poster = $('img.wp-post-image, img.size-full, .thumb img, img[src*="uploads"]').not('[src*="Movieku.png"]').first().attr('src') || '';
const synopsis = $('.entry-content').text().trim().substring(0, 500);
const genres = [];
$('a[href*="/genre/"]').each((i, el) => {
const g = $(el).text().trim();
if (g && g !== 'Genre' && !genres.includes(g)) genres.push(g);
});
const actors = [];
$('a[href*="/actor/"]').each((i, el) => {
const a = $(el).text().trim();
if (a && !actors.includes(a)) actors.push(a);
});
const directors = [];
$('a[href*="/director/"]').each((i, el) => {
const d = $(el).text().trim();
if (d && !directors.includes(d)) directors.push(d);
});
const downloads = [];
$('a[href*="acefile.co"], a[href*="mega.nz"], a[href*="drive.google.com"], a[href*="google"], a[href*="zippy"], a[href*="mediafire"]').each((i, a) => {
const label = $(a).text().trim();
const url = $(a).attr('href');
if (label && url) {
const epMatch = label.match(/eps\s*(\d+)/i) || url.match(/eps[_\s]*(\d+)/i);
const resMatch = label.match(/(\d+p)/i) || url.match(/(\d+p)/i);
const isBatch = /batch|zip|complete|end/i.test(label) || /end/i.test(url);
downloads.push({
label,
url,
episode: epMatch ? parseInt(epMatch[1]) : undefined,
resolution: resMatch ? resMatch[1] : undefined,
batch: isBatch || undefined
});
}
});
return { title, poster: poster || undefined, synopsis, genres, actors, directors, download_links: downloads };
}
function slugify(text) {
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
}
async function discoverGenresAndActors(pages = 3) {
const seriesLinks = [];
for (let p = 1; p <= pages; p++) {
const html = await fetch(BASE + '/series/page/' + p + '/');
const $ = load(html);
$('article a[href*="/series/"]').each((i, el) => {
seriesLinks.push(new URL($(el).attr('href'), BASE).href);
});
}
const genres = new Set();
const actors = new Set();
let i = 0;
for (const url of seriesLinks) {
try {
const html = await fetch(url);
const $ = load(html);
$('a[href*="/genre/"]').each((i, el) => {
const g = $(el).text().trim();
if (g && g !== 'Genre') genres.add(g);
});
$('a[href*="/actor/"]').each((i, el) => {
const a = $(el).text().trim();
if (a) actors.add(a);
});
} catch (e) {}
if (++i % 20 === 0) console.error(` discover ${i}/${seriesLinks.length}...`);
}
return {
genres: [...genres].sort().map(g => ({ name: g, slug: slugify(g), url: BASE + '/genre/' + slugify(g) + '/' })),
actors: [...actors].sort().map(a => ({ name: a, slug: slugify(a), url: BASE + '/actor/' + slugify(a) + '/' })),
};
}
async function scrapeHome() { const html = await fetch(BASE + '/'); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
async function scrapeOngoing() { const html = await fetch(BASE + '/ongoing/'); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
async function scrapeSearch(query) { const html = await fetch(BASE + '/?s=' + encodeURIComponent(query)); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
async function scrapeGenre(slug) { const html = await fetch(BASE + '/genre/' + slug + '/'); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
async function scrapeActor(name) { const html = await fetch(BASE + '/actor/' + slugify(name) + '/'); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
async function scrapeSeries(url) { const html = await fetch(url); return { creator: 'rynaqrtz', ...parseSeriesDetail(html) }; }
async function scrapeDiscover(pages = 3) { console.error(`Discovering genres & actors from ${pages} pages...`); const data = await discoverGenresAndActors(pages); return { creator: 'rynaqrtz', ...data }; }
async function scrapeSeriesList(url) { const html = await fetch(url); return { creator: 'rynaqrtz', data: parseArticles(html) }; }
module.exports = { scrapeHome, scrapeOngoing, scrapeSearch, scrapeGenre, scrapeActor, scrapeSeries, scrapeDiscover, scrapeSeriesList };
if (require.main === module) {
const args = process.argv.slice(2);
const action = args[0];
const query = args[1] || '';
const getFlag = (f, def) => { const i = args.indexOf('--' + f); return i !== -1 && i + 1 < args.length ? args[i + 1] : def; };
const pages = parseInt(getFlag('pages', '3'));
(async () => {
try {
let data;
if (action === 'home') data = await scrapeHome();
else if (action === 'ongoing') data = await scrapeOngoing();
else if (action === 'search') { if (!query) throw new Error('query needed'); data = await scrapeSearch(query); }
else if (action === 'genre') { if (!query) throw new Error('slug needed'); data = await scrapeGenre(query); }
else if (action === 'actor') { if (!query) throw new Error('actor name needed'); data = await scrapeActor(query); }
else if (action === 'series') { if (!query) throw new Error('url needed'); data = await scrapeSeries(query); }
else if (action === 'discover') { data = await scrapeDiscover(pages); }
else if (action === 'series-list') { data = await scrapeSeriesList(query || BASE + '/series/'); }
else { console.log(JSON.stringify({ usage: ['home','ongoing','search <q>','genre <slug>','actor <name>','series <url>','discover [--pages=N]','series-list [url]'] })); return; }
console.log(JSON.stringify(data, null, 2));
} catch (e) { console.error(JSON.stringify({ error: e.message })); process.exit(1); }
})();
}Rating
Gimana snippet ini menurutmu?
Embed ke website / blog
<iframe src="https://qrtzcode.vercel.app/api/embed/movie/movieku" style="width:100%;height:400px;border:none;border-radius:12px;"></iframe>