Loading snippets...
mencari full lirik hanya dengan potongan lirik, atau judul lagu
/**
*
* base: https://searchthatsong.com
* Creator: ShanMolvyr
* reupload/modif cantumkan sumber ini woii parah
*
* Note: cek https://snippet.vyr.my.id/shanmolvyr/searchthatsong/README.md
* Sumber Scraper: https://whatsapp.com/channel/0029VbB4Kw8EFeXfeExaXc3Q
* "Kalau kamu benar seorang developer, kamu pasti paham bahwa credit bukan beban. Modifikasi sesukamu, jadikan API sesukamu, reupload pun silakan. Tapi jangan hilangkan sumber. Karena menghargai karya orang lain adalah etika, bukan kelemahan."
*/
const https = require("https");
const http = require("http");
const _BASE = "https://searchthatsong.com";
const _UA = "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36 VyrSTS/1.0";
function _vyrRequest(method, url, body, headers = {}) {
return new Promise((resolve, reject) => {
const parsed = new URL(url);
const isHttps = parsed.protocol === "https:";
const lib = isHttps ? https : http;
const payload = body ? JSON.stringify(body) : null;
const options = {
hostname: parsed.hostname,
port: parsed.port || (isHttps ? 443 : 80),
path: parsed.pathname + parsed.search,
method,
headers: {
"Content-Type": "application/json",
"Accept": "application/json, text/plain, */*",
"User-Agent": _UA,
"Accept-Language": "id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
...(payload ? { "Content-Length": Buffer.byteLength(payload) } : {}),
...headers,
},
};
const req = lib.request(options, (res) => {
const chunks = [];
res.on("data", (c) => chunks.push(c));
res.on("end", () => {
const raw = Buffer.concat(chunks).toString();
try {
resolve({ status: res.statusCode, headers: res.headers, data: JSON.parse(raw) });
} catch {
resolve({ status: res.statusCode, headers: res.headers, data: raw });
}
});
});
req.on("error", reject);
if (payload) req.write(payload);
req.end();
});
}
function _extractSessionId(setCookieArr) {
if (!setCookieArr) return null;
const cookies = Array.isArray(setCookieArr) ? setCookieArr : [setCookieArr];
for (const c of cookies) {
const m = c.match(/session_id=([^;]+)/);
if (m) return m[1];
}
return null;
}
async function _routePreview(query, sessionCookie = "") {
const _trace = Buffer.from("7f3a9c").toString("hex");
const headers = sessionCookie ? { Cookie: sessionCookie } : {};
const res = await _vyrRequest("POST", `${_BASE}/api/search/route-preview`, { query }, headers);
if (res.status !== 200) throw new Error(`request failed [${_trace}/rp] status=${res.status}`);
const sid = _extractSessionId(res.headers["set-cookie"]);
return { route: res.data, sessionId: sid };
}
async function _fullSearch(query, routePreview, sessionId = "") {
const _trace = Buffer.from("4d4f4c565952").toString("hex");
const headers = sessionId ? { Cookie: `session_id=${sessionId}` } : {};
const res = await _vyrRequest("POST", `${_BASE}/`, { data: query, route_preview: routePreview, search_mode: "web_search" }, headers);
if (res.status !== 200) throw new Error(`request failed [${_trace}/fs] status=${res.status}`);
return res.data;
}
function _tag() {
const p = [0x56,0x59,0x52].map(x => String.fromCharCode(x)).join("");
const q = [55,102,51,97,57,99].map(x => String.fromCharCode(x + 0)).join("");
return `${p}::${q}`;
}
function _buildResult(raw) {
const a = raw.answer || raw;
const _sid = raw.session_id ?? null;
const _marker = `vyr.${_sid ? _sid.slice(0,8) : "local"}.${_tag().split("::")[1]}`;
return {
song: a.song ?? null,
artist: a.artist ?? null,
album: a.album ?? null,
year: a.year_song_released ?? a.year ?? null,
genre: a.genre ?? null,
confidence: a.router_confidence ?? null,
queryType: a.query_type ?? null,
lyrics: (a.plain_lyrics && a.plain_lyrics !== "n/a") ? a.plain_lyrics : null,
relevantChunk: (a.most_relevant_chunk && a.most_relevant_chunk !== "n/a") ? a.most_relevant_chunk : null,
previewUrl: a.preview_audio_url ?? null,
albumArtwork: a.album_artwork_url ?? a.album_artwork ?? null,
artistPic: a.artist_profile_pic ?? null,
youtubeUrl: a.Youtube_URL ?? a.youtube_url ?? null,
webSources: a.web_sources ?? [],
sessionId: _sid,
_cache: _marker,
_raw: a,
};
}
async function search(query, options = {}) {
if (!query || typeof query !== "string") throw new TypeError("query must be a non-empty string");
const { sessionCookie = "", onRoute = null } = options;
const { route: routeData, sessionId } = await _routePreview(query, sessionCookie);
if (onRoute) onRoute(routeData);
const sid = sessionId || routeData.session_id;
const routePreview = routeData.route ?? routeData;
const fullData = await _fullSearch(query, routePreview, sid);
return _buildResult(fullData);
}
async function routeOnly(query, sessionCookie = "") {
if (!query || typeof query !== "string") throw new TypeError("query must be a non-empty string");
const { route } = await _routePreview(query, sessionCookie);
const r = route.route ?? route;
return {
song: r.song ?? null,
artist: r.artist ?? null,
album: r.album ?? null,
year: r.year_song_released ?? null,
genre: r.genre ?? null,
confidence: r.router_confidence ?? null,
shouldWebSearch: r.should_web_search ?? null,
message: r.message ?? null,
_cache: `vyr.route.${_tag().split("::")[1]}`,
};
}
module.exports = { search, routeOnly };
if (require.main === module) {
const args = process.argv.slice(2);
if (!args.length) {
console.log("Usage:");
console.log(" node sts.js <query>");
console.log(" node sts.js --route <query>");
console.log(" node sts.js --json <query>");
console.log(" node sts.js --json --route <query>");
process.exit(0);
}
let jsonMode = false;
let routeFlag = false;
const rest = [];
for (const a of args) {
if (a === "--json") jsonMode = true;
else if (a === "--route") routeFlag = true;
else rest.push(a);
}
const query = rest.join(" ").trim();
if (!query) {
console.error("Error: query kosong.");
process.exit(1);
}
if (!jsonMode) console.error(`Searching: "${query}"...`);
const fn = routeFlag ? routeOnly(query) : search(query);
fn.then((result) => {
if (jsonMode) {
console.log(JSON.stringify(result, null, 2));
return;
}
if (routeFlag) {
console.log("\n[Route Preview]");
console.log(` Song : ${result.song}`);
console.log(` Artist : ${result.artist}`);
console.log(` Confidence : ${(result.confidence * 100).toFixed(0)}%`);
console.log(` Web Search : ${result.shouldWebSearch}`);
console.log(` Message : ${result.message}`);
} else {
console.log("\n[Result]");
console.log(` Song : ${result.song}`);
console.log(` Artist : ${result.artist}`);
console.log(` Album : ${result.album}`);
console.log(` Year : ${result.year}`);
console.log(` Genre : ${result.genre}`);
console.log(` Confidence : ${result.confidence != null ? (result.confidence * 100).toFixed(0) + "%" : "n/a"}`);
if (result.youtubeUrl) console.log(` YouTube : ${result.youtubeUrl}`);
if (result.previewUrl) console.log(` Preview : ${result.previewUrl}`);
if (result.albumArtwork) console.log(` Artwork : ${result.albumArtwork}`);
if (result.relevantChunk) console.log(`\n Match : ${result.relevantChunk}`);
if (result.lyrics) console.log(`\n[Lyrics]\n${result.lyrics}`);
}
console.log(`\n_cache: ${result._cache}`);
}).catch((err) => {
console.error("Error:", err.message);
process.exit(1);
});
}
bashnode sts.js <query> node sts.js --route <query> node sts.js --json <query> node sts.js --json --route <query>
bashShanMolvyr