Loading snippets...
scraper LayarKaca21 versi lebih anu lagi, get home, detail(data, watch), search, default movie Indonesia
/**
* 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 };
// CLI
if (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);
}
})();
}
bashnpm install axios cheerio
bashUsage: 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
bashdefault nya film Indonesia tuh coba aja home, detail pake url atau slug, dan coba search