LayarKaca21
scraper LayarKaca21 versi lebih anu lagi, get home, detail(data, watch), search, default movie Indonesia
12 Juni 2026902 file
layarkaca21.jsjavascript · 240 baris
/** * LayarKaca21 wrapper home, detail, search * base: https://bridgestoabrighterfuture.org * Creator: ShanMolvyr * Jangan Hapus Kreator hargai creator LAH hehe * Note: cek https://snippet.vyr.my.id/shanmolvyr/layarkaca21/README.md * Sumber: https://whatsapp.com/channel/0029VbB4Kw8EFeXfeExaXc3Q */const axios = require("axios");const cheerio = require("cheerio");const BASE = "https://bridgestoabrighterfuture.org";const CREDIT = "Shanvyr";const ADULT_GENRES = new Set([ "jav", "film-semi", "film-semi-barat", "film-semi-jepang", "semi-jepang", "film-semi-korea", "semi-korea", "film-semi-philippines", "xtube", "none",]);const ADULT_PATTERN = /\b(jav|bokep|xxx|18\+|dewasa|porno|indoviral|film semi)\b/i;function isAdult(title = "", genres = []) { if (ADULT_PATTERN.test(title)) return true; return genres.some(g => ADULT_GENRES.has(g.toLowerCase().replace(/\s+/g, "-")));}const http = axios.create({ baseURL: BASE, timeout: 15000, headers: { "User-Agent": "Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 Chrome/124 Safari/537.36", "Accept-Language": "id-ID,id;q=0.9", Referer: BASE, },});async function get(path, params = {}) { const res = await http.get(path, { params }); return cheerio.load(res.data);}function parseMovieCard($, el) { const $el = $(el); const title = $el.find(".entry-title a").text().trim(); const url = $el.find(".entry-title a").attr("href") || ""; const slug = url.replace(BASE, "").replace(/\//g, ""); const thumb = $el.find(".content-thumbnail img").attr("src") || ""; const rating = $el.find(".gmr-rating-item").text().replace(/[^\d.]/g, "").trim(); const duration = $el.find(".gmr-duration-item").text().replace(/[^\d\s]/g, "").trim(); const trailer = $el.find(".gmr-trailer-popup").attr("href") || ""; const genres = [], countries = []; $el.find(".gmr-movie-on a").each((_, a) => { const href = $(a).attr("href") || ""; if (href.includes("/country/")) countries.push($(a).text().trim()); else genres.push($(a).text().trim()); }); return { title, slug, url, thumb, rating, duration, genres, countries, trailer };}function applyFilters(movies, { country, filterAdult }) { return movies.filter(m => { if (country && !m.countries.some(c => c.toLowerCase() === country.toLowerCase())) return false; if (filterAdult && isAdult(m.title, m.genres)) return false; return true; });}// opts: { country="indonesia", filterAdult=true, page=1 }async function home(opts = {}) { const { country = "indonesia", filterAdult = true, page = 1 } = opts; const base = country ? `/country/${country}` : ""; const url = page > 1 ? `${base}/page/${page}/` : `${base || "/"}/`; const $ = await get(url); const movies = []; $("#gmr-main-load article, .gmr-grid article").each((_, el) => { movies.push(parseMovieCard($, el)); }); return { credit: CREDIT, page, country: country || "all", movies: applyFilters(movies, { country: null, filterAdult }) };}// opts: { country="indonesia", filterAdult=true, year="", genre="", page=1 }async function search(query, opts = {}) { const { country = "indonesia", filterAdult = true, year = "", genre = "", page = 1 } = opts; const params = { s: query, search: "advanced", post_type: "movie" }; if (year) params.movieyear = year; if (genre) params.genre = genre; if (page > 1) params.paged = page; const $ = await get("/", params); const movies = []; $("#gmr-main-load article, .gmr-grid article, #primary article").each((_, el) => { movies.push(parseMovieCard($, el)); }); return { credit: CREDIT, query, page, movies: applyFilters(movies, { country, filterAdult }) };}// opts: { filterAdult=true }async function detail(slugOrUrl, opts = {}) { const { filterAdult = true } = opts; const path = slugOrUrl.startsWith("http") ? slugOrUrl.replace(BASE, "") : `/${slugOrUrl}/`; const $ = await get(path); const title = $(".entry-title[itemprop='name'], h1.entry-title").first().text().trim(); const thumb = $(".gmr-movie-data img").first().attr("src") || ""; const synopsis = $(".entry-content-single p").first().text().trim(); const rating = $("[itemprop='ratingValue']").text().trim(); const votes = $("[itemprop='ratingCount']").text().trim(); const trailer = $(".gmr-trailer-popup").attr("href") || ""; const embed = $(".gmr-embed-responsive iframe, .gmr-pagi-player iframe").first().attr("src") || ""; const meta = {}; $(".gmr-moviedata").each((_, el) => { const key = $(el).find("strong").text().replace(":", "").trim().toLowerCase(); const val = $(el).text().replace($(el).find("strong").text(), "").trim(); meta[key] = val; }); const genres = []; $(".gmr-moviedata a[rel='category tag']").each((_, a) => { const href = $(a).attr("href") || ""; if (!href.includes("/country/")) genres.push($(a).text().trim()); }); const cast = []; $("[itemprop='actors'] [itemprop='name']").each((_, el) => cast.push($(el).text().trim())); const servers = []; $(".muvipro-player-tabs a").each((_, a) => { servers.push({ label: $(a).text().trim(), url: $(a).attr("href") || "" }); }); if (filterAdult && isAdult(title, genres)) return { credit: CREDIT, error: "filtered", title }; return { credit: CREDIT, title, thumb, synopsis, rating, votes, trailer, embed, servers, cast, meta };}// opts: { country="indonesia", filterAdult=true, page=1 }async function genre(genreSlug, opts = {}) { const { country = "indonesia", filterAdult = true, page = 1 } = opts; const url = page > 1 ? `/${genreSlug}/page/${page}/` : `/${genreSlug}/`; const $ = await get(url); const movies = []; $("#gmr-main-load article, .gmr-grid article").each((_, el) => { movies.push(parseMovieCard($, el)); }); return { credit: CREDIT, genre: genreSlug, page, movies: applyFilters(movies, { country, filterAdult }) };}// opts: { country="indonesia", filterAdult=true, page=1 }async function year(y, opts = {}) { const { country = "indonesia", filterAdult = true, page = 1 } = opts; const url = page > 1 ? `/year/${y}/page/${page}/` : `/year/${y}/`; const $ = await get(url); const movies = []; $("#gmr-main-load article, .gmr-grid article").each((_, el) => { movies.push(parseMovieCard($, el)); }); return { credit: CREDIT, year: y, page, movies: applyFilters(movies, { country, filterAdult }) };}// opts: { country="indonesia", filterAdult=true, page=1 }async function bestRating(opts = {}) { const { country = "indonesia", filterAdult = true, page = 1 } = opts; const url = page > 1 ? `/best-rating/page/${page}/` : `/best-rating/`; const $ = await get(url); const movies = []; $("#gmr-main-load article, .gmr-grid article").each((_, el) => { movies.push(parseMovieCard($, el)); }); return { credit: CREDIT, page, movies: applyFilters(movies, { country, filterAdult }) };}module.exports = { home, search, detail, genre, year, bestRating };// CLIif (require.main === module) { const [,, cmd, ...args] = process.argv; // parse --key=value flags const flags = {}; const positional = []; for (const a of args) { const m = a.match(/^--(\w+)=?(.*)?$/); if (m) flags[m[1]] = m[2] === undefined ? true : m[2]; else positional.push(a); } const opts = { country: flags.country ?? "indonesia", filterAdult: flags.adult === "false" ? false : true, page: Number(flags.page) || 1, year: flags.year || "", genre: flags.genre || "", }; (async () => { try { let result; if (cmd === "home") result = await home(opts); else if (cmd === "search") result = await search(positional[0], opts); else if (cmd === "detail") result = await detail(positional[0], opts); else if (cmd === "genre") result = await genre(positional[0], opts); else if (cmd === "year") result = await year(positional[0], opts); else if (cmd === "best") result = await bestRating(opts); else { console.log([ "Usage: node lk21.js <cmd> [args] [flags]", "", "Commands:", " home Film Indonesia terbaru", " search <query> Cari film", " detail <slug-or-url> Detail film", " genre <slug> Film per genre", " year <yyyy> Film per tahun", " best Film rating terbaik", "", "Flags:", " --country=<name> Default: indonesia (kosongkan: --country=)", " --adult=false Tampilkan konten dewasa", " --page=<n> Halaman", " --year=<yyyy> Filter tahun (search only)", " --genre=<slug> Filter genre (search only)", "", "Contoh:", " node lk21.js search \"agak laen\"", " node lk21.js home --country= --adult=false", " node lk21.js genre drama --country=korea", " node lk21.js best --page=2", ].join("\n")); process.exit(0); } console.log(JSON.stringify(result, null, 2)); } catch (e) { console.error(JSON.stringify({ error: e.message }, null, 2)); process.exit(1); } })();}README.mdmarkdown · 34 baris
Komentar
Masuk untuk ikut berkomentar.
Belum ada komentar.