Back to Home
Gistify Snippet
Public
Scraper ytmusic-search
Scraper ytmusic-search
#github-gist#javascript#gist:b49594fd012ce7f07769acfcf9984478#gistsync:2026-09-02T12:40:32Z
1
Rawytmusic-search.jsjavascript
129 lines| 1 | |
| 2 | |
| 3 | import * as __ns_494 from 'axios' |
| 4 | const axios = __ns_494.default |
| 5 | import * as __ns_495 from 'node:url' |
| 6 | const pathToFileURL = __ns_495.pathToFileURL |
| 7 | |
| 8 | async function searchYTMusic(query) { |
| 9 | const url = 'https://music.youtube.com/youtubei/v1/music/get_search_suggestions?prettyPrint=false'; |
| 10 | const payload = { |
| 11 | context: { |
| 12 | client: { |
| 13 | clientName: 'WEB_REMIX', |
| 14 | clientVersion: '1.20230509.00.00', |
| 15 | hl: 'id', |
| 16 | gl: 'ID' |
| 17 | } |
| 18 | }, |
| 19 | input: query |
| 20 | }; |
| 21 | |
| 22 | const headers = { |
| 23 | 'Content-Type': 'application/json' |
| 24 | }; |
| 25 | |
| 26 | try { |
| 27 | const response = await axios.post(url, payload, { headers }); |
| 28 | const contents = response.data.contents || []; |
| 29 | const searchResults = []; |
| 30 | |
| 31 | contents.forEach(section => { |
| 32 | const sectionData = section.searchSuggestionsSectionRenderer || {}; |
| 33 | const items = sectionData.contents || []; |
| 34 | |
| 35 | items.forEach(item => { |
| 36 | if (item.searchSuggestionRenderer) { |
| 37 | const suggestion = item.searchSuggestionRenderer.suggestion || {}; |
| 38 | const text = suggestion.runs ? suggestion.runs.map(r => r.text).join('') : ''; |
| 39 | if (text) { |
| 40 | searchResults.push({ |
| 41 | type: 'suggestion_text', |
| 42 | title: text |
| 43 | }); |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | if (item.musicResponsiveListItemRenderer) { |
| 48 | const listItem = item.musicResponsiveListItemRenderer; |
| 49 | const videoId = listItem.playlistItemData?.videoId || listItem.navigationEndpoint?.watchEndpoint?.videoId; |
| 50 | |
| 51 | let title = ''; |
| 52 | let artist = ''; |
| 53 | |
| 54 | if (listItem.flexColumns) { |
| 55 | const col1 = listItem.flexColumns[0]?.musicResponsiveListItemFlexColumnRenderer?.text?.runs; |
| 56 | if (col1) title = col1.map(r => r.text).join(''); |
| 57 | |
| 58 | const col2 = listItem.flexColumns[1]?.musicResponsiveListItemFlexColumnRenderer?.text?.runs; |
| 59 | if (col2) artist = col2.map(r => r.text).join(''); |
| 60 | } |
| 61 | |
| 62 | if (title && videoId) { |
| 63 | searchResults.push({ |
| 64 | type: 'music_item', |
| 65 | title: title, |
| 66 | artist: artist.replace(/ • /g, ' '), |
| 67 | video_id: videoId, |
| 68 | watch_link: 'https://music.youtube.com/watch?v=' + videoId |
| 69 | }); |
| 70 | } |
| 71 | } |
| 72 | }); |
| 73 | }); |
| 74 | |
| 75 | return { |
| 76 | success: true, |
| 77 | total: searchResults.length, |
| 78 | results: searchResults |
| 79 | }; |
| 80 | |
| 81 | } catch (error) { |
| 82 | return { |
| 83 | success: false, |
| 84 | error: error.response ? error.response.data : error.message |
| 85 | }; |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { |
| 90 | const __exports = { searchYTMusic: searchYTMusic } |
| 91 | const __fns = Object.fromEntries(Object.entries(__exports).filter(([, v]) => typeof v === 'function')) |
| 92 | const __names = Object.keys(__fns) |
| 93 | if (__names.length === 0) { |
| 94 | console.log('Tidak ada fungsi yang bisa di-demo. Import modul ini dari kode lain.') |
| 95 | } else { |
| 96 | const __search = __names.find((n) => /search|cari/i.test(n)) |
| 97 | const __name = __search || __names[0] |
| 98 | const __fn = __fns[__name] |
| 99 | const __isClass = /^class\s/.test(Function.prototype.toString.call(__fn)) |
| 100 | const __defaultArgs = (() => { |
| 101 | const n = __name.toLowerCase() |
| 102 | if (/emoji/.test(n)) return [{ emoji: '😀😃' }] |
| 103 | if (/textpro|generate.*text|effect/.test(n)) return ['neon', 'Hello'] |
| 104 | if (/image|wallpaper|search|query|anime|movie|manga|news|lyrics|wiki|quote|stalk|detail/.test(n)) return ['naruto'] |
| 105 | if (/download|youtube|video|audio|music|spotify|tiktok|instagram|facebook|twitter|reels|terabox|media/.test(n)) return ['https://www.youtube.com/watch?v=dQw4w9WgXcQ'] |
| 106 | if (/dork/.test(n)) return ['example.com', 'documents'] |
| 107 | if (/tts|speech|prompt|chat|ask|translate/.test(n)) return ['Hello world'] |
| 108 | if (/parse|format|normalize|list|features/.test(n)) return [] |
| 109 | return ['test'] |
| 110 | })() |
| 111 | let __args = __defaultArgs |
| 112 | if (process.argv.length > 2) __args = process.argv.slice(2).map((a) => { try { return JSON.parse(a) } catch { return a } }) |
| 113 | if (__args.length === 0 && !__search && !__isClass && __fn.length > 0) { |
| 114 | console.log('Fungsi: ' + __names.join(', ')) |
| 115 | console.log('Contoh: node ' + "ytmusic-search.js" + ' ' + __name + ' <arg>') |
| 116 | } else { |
| 117 | ;(async () => { |
| 118 | try { |
| 119 | const r = __isClass ? new __fn(...__args) : await __fn(...__args) |
| 120 | console.log(JSON.stringify(r, null, 2)) |
| 121 | } catch (e) { |
| 122 | console.error('Error: ' + (e && e.message ? e.message : e)) |
| 123 | process.exitCode = 1 |
| 124 | } |
| 125 | })() |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | |
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.