Back to Home
Gistify Snippet
kyiov
Sep 3ยท1 file(s)
Public

Scraper ytstalk

Scraper ytstalk

#github-gist#javascript#gist:24b1696bd5a386d490f22dedf34fb5b2#gistsync:2026-09-02T12:40:43Z
2
Raw
ytstalk.jsjavascript
128 lines
1
2
3import * as __ns_873 from 'axios'
4const axios = __ns_873.default
5import * as __ns_874 from 'node:url'
6const pathToFileURL = __ns_874.pathToFileURL
7
8async function stalkYT(query) {
9 if (!query) throw new Error('Masukkan username/handle YouTube.')
10 const clean = query
11 .trim()
12 .replace(/^https?:\/\/(www\.)?youtube\.com\//i, '')
13 .replace(/^@/, '')
14 .split(/[/?#]/)[0]
15
16 const url = `https://www.youtube.com/@${clean}`
17
18 try {
19 const { data: html } = await axios.get(url, {
20 headers: {
21 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
22 'Accept-Language': 'id-ID,id;q=0.9,en-US;q=0.8'
23 },
24 timeout: 15000
25 })
26
27 const m = html.match(/ytInitialData\s*=\s*({.+?});<\/script>/)
28 if (!m) throw new Error('Gagal membaca struktur halaman YouTube.')
29 const data = JSON.parse(m[1])
30 const meta = data.metadata?.channelMetadataRenderer || {}
31 const header = data.header?.pageHeaderRenderer || data.header?.c4TabbedHeaderRenderer || {}
32
33 const name = meta.title || clean
34 const bio = meta.description || 'Tidak ada deskripsi.'
35 const avatar = meta.avatar?.thumbnails?.slice(-1)[0]?.url || header?.content?.pageHeaderViewModel?.image?.decoratedAvatarViewModel?.avatar?.avatarViewModel?.image?.sources?.slice(-1)[0]?.url || `https://avatar.iran.liara.run/public/boy?username=${encodeURIComponent(clean)}`
36 const channelUrl = meta.channelUrl || `https://www.youtube.com/@${clean}`
37
38 let subscribers = '-'
39 let videos = '-'
40
41 const rows = header?.content?.pageHeaderViewModel?.metadata?.contentMetadataViewModel?.metadataRows || []
42 for (const r of rows) {
43 for (const part of r.metadataParts || []) {
44 const txt = part.text?.content || ''
45 if (/subscriber|pelanggan/i.test(txt)) subscribers = txt
46 if (/video/i.test(txt)) videos = txt
47 }
48 }
49
50 return {
51 name,
52 username: clean,
53 bio,
54 avatar,
55 subscribers,
56 videos,
57 url: channelUrl
58 }
59 } catch (err) {
60 const searchUrl = `https://www.youtube.com/results?search_query=${encodeURIComponent(query)}&sp=EgIQAg%253D%253D`
61 const { data: html2 } = await axios.get(searchUrl, {
62 headers: {
63 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
64 },
65 timeout: 15000
66 })
67 const m2 = html2.match(/ytInitialData\s*=\s*({.+?});<\/script>/)
68 if (!m2) throw new Error(`Channel YouTube "@${clean}" tidak ditemukan.`)
69 const data2 = JSON.parse(m2[1])
70 const channelRenderer = data2.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents?.[0]?.itemSectionRenderer?.contents?.find(c => c.channelRenderer)?.channelRenderer
71
72 if (!channelRenderer) throw new Error(`Channel YouTube "@${clean}" tidak ditemukan.`)
73
74 return {
75 name: channelRenderer.title?.simpleText || clean,
76 username: clean,
77 bio: channelRenderer.descriptionSnippet?.runs?.map(r => r.text).join('') || 'Tidak ada deskripsi.',
78 avatar: channelRenderer.thumbnail?.thumbnails?.slice(-1)[0]?.url || '',
79 subscribers: channelRenderer.videoCountText?.simpleText || channelRenderer.subscriberCountText?.simpleText || '-',
80 videos: channelRenderer.videoCountText?.simpleText || '-',
81 url: `https://www.youtube.com/${channelRenderer.navigationEndpoint?.commandMetadata?.webCommandMetadata?.url || '@' + clean}`
82 }
83 }
84}
85
86const __dflt_36 = { stalkYT }
87
88if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
89 const __exports = { stalkYT: stalkYT, default: __dflt_36 }
90 const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function'))
91 const __names = Object.keys(__fns)
92 if (__names.length === 0) {
93 console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.')
94 } else {
95 const __search = __names.find((n) => /search|cari/i.test(n))
96 const __name = __search || __names[0]
97 const __fn = __fns[__name]
98 const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn))
99 const __defaultArgs = (() => {
100 const n = __name.toLowerCase()
101 if (/emoji/.test(n)) return [{ emoji: '๐Ÿ˜€๐Ÿ˜ƒ' }]
102 if (/textpro|generate.*text|effect/.test(n)) return ['neon', 'Hello']
103 if (/image|wallpaper|search|query|anime|movie|manga|news|lyrics|wiki|quote|stalk|detail/.test(n)) return ['naruto']
104 if (/download|youtube|video|audio|music|spotify|tiktok|instagram|facebook|twitter|reels|terabox|media/.test(n)) return ['https://www.youtube.com/watch?v=dQw4w9WgXcQ']
105 if (/dork/.test(n)) return ['example.com', 'documents']
106 if (/tts|speech|prompt|chat|ask|translate/.test(n)) return ['Hello world']
107 if (/parse|format|normalize|list|features/.test(n)) return []
108 return ['test']
109 })()
110 let __args = __defaultArgs
111 if (process.argv.length > 2) __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } })
112 if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) {
113 console.log('Fungsi: ' + __names.join(', '))
114 console.log('Contoh: node ' + "ytstalk.js" + ' ' + __name + ' <arg>')
115 } else {
116 ;(async () => {
117 try {
118 const r = __isClass ? new __fn(...__args) : await __fn(...__args)
119 console.log(JSON.stringify(r, null, 2))
120 } catch (e) {
121 console.error('Error: ' + (e && e.message ? e.message : e))
122 process.exitCode = 1
123 }
124 })()
125 }
126 }
127}
128
Discussion & Comments0

No comments yet โ€” be the first to leave feedback or start a code discussion.

Sign in with your GitHub account to write comments and join the discussion.