(() => { var __webpack_exports__ = {}; console.log("bundle2!"), printable = e => "WEB" === e, parseCodecs = e => { const t = e.mimeType; if (!t) return {}; const n = t.match(/(?[^/]+\/[^;]+)(?:;\s*codecs="?(?[^"]+))?/); if (!n) return {}; const o = n.groups.codecs; if (!o) return {}; const s = o.trim().replace(/,$/, "").split(",").map((e => e.trim())).filter(Boolean); let i = null, c = null; for (const e of s) { const t = e.split(".")[0]; ["avc1", "avc2", "avc3", "avc4", "vp9", "vp8", "hev1", "hev2", "h263", "h264", "mp4v", "hvc1", "av01", "theora"].includes(t) ? i || (i = e) : ["mp4a", "opus", "vorbis", "mp3", "aac", "ac-3", "ec-3", "eac3", "dtsc", "dtse", "dtsh", "dtsl"].includes(t) ? c || (c = e) : console.log(`WARNING: Unknown codec ${e}`) } return i || c ? {vcodec: i, acodec: c} : 2 === s.length ? {vcodec: s[0], acodec: s[1]} : {} }, parseSetCookie = e => { if (!e) return ""; const t = e["Set-Cookie"]; if (!t) return ""; console.log(`setCookie: ${t}`); let n = "PREF=hl=en&tz=UTC; SOCS=CAI; GPS=1; "; const o = ["YSC", "VISITOR_INFO1_LIVE", "VISITOR_PRIVACY_METADATA"]; for (const e in o) { const s = o[e], i = new RegExp(`${s}=([^;,]+)`), c = t.match(i); if (c && 2 === c.length) { const t = c[1]; n += e != o.length - 1 ? `${s}=${t}; ` : `${s}=${t}` } } return console.log(`current cookie: ${n}`), n }, request = async (e, t, n = null, o = {}, s) => { if ("WEB" === s && (t = t.replace("https://www.youtube.com", "http://127.0.0.1")), console.log(`request url:${t}`), console.log(`request data:${n}`), console.log(`request method:${e}`), console.log(`request headers:${JSON.stringify(o)}`), "WEB" === s) { const s = await fetch(t, {mode: "cors", method: e, headers: o, body: n}), i = await s.text(); return Promise.resolve({data: i, headers: s.headers}) } return new Promise(((s, i) => { AF.request(t, e, n, o, ((e, t, n) => { n ? i(n) : (console.log(`response headers: ${t}`), s({data: e, headers: JSON.parse(t)})) })) })) }, getStringBetween = (e, t, n, o = 0, s = 0) => { const i = e.indexOf(t), c = n ? e.indexOf(n, i) : e.length; return e.substring(i + t.length + s, c + o) }, findFunction = (jsCode, regexp, platform) => { const match = jsCode.match(regexp); if (!match && match.length <= 1) return null; let result = ""; const dependencyMatches = match[0].match(/([$a-zA-Z0-9]+\.[$a-zA-Z0-9]+)/g), existDependencies = []; if (dependencyMatches && dependencyMatches.length >= 1) for (let e of dependencyMatches) { const t = e.split(".")[0]; if (existDependencies.includes(t)) continue; const n = jsCode.match(new RegExp(`var \\${t}={(.|\\n)*?};`), "ig"); n && n.length >= 1 && (result += n[0] + "\n"), existDependencies.push(t) } return result += `\n${match[0]}`, printable(platform) && console.log("decipherFunction result: " + result), eval(result) }; const cache = {}; fetchBaseJSContent = async (e, t) => { const n = `jsContent:${e}`; if (cache[n]) return console.log(`baseContent from cache: ${e}`), cache[n]; console.log(`extract baseUrl: ${e}`); const o = await request("GET", e, null, {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.101 Safari/537.36"}, t), { data: s, _: i } = o; return cache[n] = s, s }, extractJSSignatureFunction = async (e, t) => { const n = `jsSign:${e}`; if (cache[n]) return console.log(`jsSign from cache: ${e}`), cache[n]; const o = await fetchBaseJSContent(e, t), s = findFunction(o, /([a-zA-Z0-9]+)=function\([a-zA-Z0-9]+\)\{a=a\.split\(""\).*};/, t); return cache[n] = s, s }, extractNJSFunction = async (e, t) => { const n = `jsN:${e}`; if (cache[n]) return console.log(`jsN from cache: ${e}`), cache[n]; const o = await fetchBaseJSContent(e, t), s = findFunction(o, /([a-zA-Z0-9]+)=function\([a-zA-Z0-9]+\)\{var b=a\.split\(""\)[\s\S]*?};/, t); return cache[n] = s, s }, signUrl = async (e, t, n) => { const o = {}; for (const t of e.split("&")) { const [e, n] = t.split("="); o[decodeURIComponent(e)] = decodeURIComponent(n) } const [s, i, c] = [o.url, o.s, o.sp], r = await extractJSSignatureFunction(t, n); if (!r) return null; printable(n) && console.log(`signatureCipher=${e}, url=${s}, signature=${i}, sp=${c}`); let a = `${s}&${c}=${r(i)}`; for (const e of s.split("&")) { const [t, n] = e.split("="); o[decodeURIComponent(t)] = decodeURIComponent(n) } const l = await extractNJSFunction(t, n), u = o.n; if (u && l) { return function d(e, t, n) { let o = new RegExp(`([?&])${t}=.*?(&|$)`, "i"), s = e.replace(o, `$1${t}=${n}$2`); return s === e && -1 === e.indexOf("?") ? s += `?${t}=${n}` : s === e && (s += `&${t}=${n}`), s }(a, "n", l(u)) } return a }, detail = async (e, t) => { try { const n = await request("GET", `${e}&bpctr=9999999999&has_verified=1`, null, { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36", Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "en-us,en;q=0.5", "Sec-Fetch-Mode": "navigate", "Accept-Encoding": "gzip, deflate, br", Cookie: "PREF=hl=en&tz=UTC; SOCS=CAI" }, t); let {data: o, headers: s} = n, i = /var ytInitialPlayerResponse\s*=\s*({.*?});/, c = o.match(i); if (!c || !c.length) throw console.log("can not found JSON: ytInitialPlayerResponse"), new Error("JSON not found: ytInitialPlayerResponse"); const r = JSON.parse(c[1]); printable(t) && console.log(r); const a = r.videoDetails, l = []; for (const e of a.thumbnail.thumbnails) l.push({url: e.url, width: e.width + "", height: e.height + ""}); let u = []; const d = []; for (const e of r.streamingData.formats.concat(r.streamingData.adaptiveFormats)) e && (e.from = "web", d.push(e)); u = u.concat(d), console.log(`after html, format size:${u.length}`); const h = `https://www.youtube.com${JSON.parse(o.match(/set\(({.+?})\);/)[1]).PLAYER_JS_URL}`; let p = []; const m = []; for (let e of u) if (printable(t) && console.log(e), e && -1 === p.indexOf(e.itag) && (e.url || (e.url = await signUrl(e.signatureCipher, h, t)), e.url)) { const {vcodec: n, acodec: o} = parseCodecs(e); if (n && o) { const s = { width: e.width + "", height: e.height + "", type: e.mimeType, quality: e.quality, itag: e.itag, fps: e.fps + "", bitrate: e.bitrate + "", url: e.url, ext: "mp4", vcodec: n, acodec: o, vbr: "0", abr: "0", container: "mp4_dash", from: e.from }; "WEB" === t && (s.source = e), m.push(s), p.push(e.itag) } } const g = o.match(/var ytInitialData\s*=\s*({.*?});/), f = []; if (g && 2 === g.length) { const e = JSON.parse(g[1]); printable(t) && console.log(e); for (const t of e.contents?.twoColumnWatchNextResults?.secondaryResults?.secondaryResults?.results || []) if (t.compactVideoRenderer) { const e = t.compactVideoRenderer; console.log(`recommend video: ${JSON.stringify(e)}`), e.videoId && f.push({ type: "gridVideoRenderer", videoId: e.videoId, title: e.title?.simpleText, thumbnails: e.thumbnail?.thumbnails, channelName: e.longBylineText?.runs?.[0]?.text, publishedTimeText: e.publishedTimeText?.simpleText, viewCountText: e.viewCountText?.simpleText, shortViewCountText: e.shortViewCountText?.simpleText, lengthText: e.lengthText?.simpleText }) } } const x = { code: 200, msg: "", data: { videoDetails: { isLiveContent: a.isLiveContent, title: a.title, thumbnails: l, description: a.shortDescription, lengthSeconds: a.lengthSeconds, viewCount: a.viewCount, keywords: a.keywords, author: a.author, channelID: a.channelId, recommendInfo: f, channelURL: `https://www.youtube.com/channel/${a.channelId}`, videoId: a.videoId }, streamingData: {formats: m.reverse()} }, id: "MusicDetailViewModel_detail_url" }; return console.log(`detail result: ${JSON.stringify(x)}`), x } catch (e) { const t = {code: -1, msg: e.toString()}; return console.log(`detail result error: ${JSON.stringify(t)}`), console.log(e), t } }, search = async (e, t, n) => { try { if (console.log(`search keyword: ${e}`), console.log(`search next: ${t}`), t) { const e = JSON.parse(t), o = e.key, s = { context: {client: {clientName: "WEB", clientVersion: "2.20240506.01.00"}}, continuation: e.continuation }; let i = await request("POST", `https://www.youtube.com/youtubei/v1/search?key=${o}`, JSON.stringify(s), {}, n); const {data: c, _: r} = i; i = JSON.parse(c); const a = []; for (const e of i.onResponseReceivedCommands[0].appendContinuationItemsAction.continuationItems[0].itemSectionRenderer.contents) { const t = e.videoRenderer; printable(n) && console.log(t), t && t.videoId && a.push({ type: "videoWithContextRenderer", data: { videoId: t.videoId, title: t.title?.runs?.[0]?.text, thumbnails: t.thumbnail?.thumbnails, channelName: t.longBylineText?.runs?.[0]?.text, publishedTimeText: t.publishedTimeText?.simpleText, viewCountText: t.viewCountText?.simpleText, shortViewCountText: t.shortViewCountText?.simpleText, lengthText: t.lengthText?.simpleText } }) } const l = { code: 200, msg: "", data: { data: a, next: JSON.stringify({ key: e.key, continuation: i.onResponseReceivedCommands?.[0]?.appendContinuationItemsAction?.continuationItems?.[1]?.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token }) }, id: "MusicSearchResultViewModel_search_result" }; return console.log(`[next] search result: ${JSON.stringify(l)}`), l } { let t = `https://www.youtube.com/results?q=${encodeURIComponent(e)}&sp=EgIQAQ%253D%253D`; const o = await request("GET", t, null, {}, n), {data: s, _: i} = o; let c = /var ytInitialData\s*=\s*({.*?});/, r = s.match(c); if (!r || !r.length) throw console.log("can not found ytInitialData"), new Error("JSON not found: ytInitialData"); const a = JSON.parse(r[1]), l = []; for (const e of a.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents?.[0]?.itemSectionRenderer?.contents) if (e.videoRenderer) { const t = e.videoRenderer; printable(n) && console.log(t), t && t.videoId && l.push({ type: "videoWithContextRenderer", data: { videoId: t.videoId, title: t.title?.runs?.[0]?.text, thumbnails: t.thumbnail?.thumbnails, channelName: t.longBylineText?.runs?.[0]?.text, publishedTimeText: t.publishedTimeText?.simpleText, viewCountText: t.viewCountText?.simpleText, shortViewCountText: t.shortViewCountText?.simpleText, lengthText: t.lengthText?.simpleText } }) } let u = {}; s.split("innertubeApiKey").length > 0 && (u.key = s.split("innertubeApiKey")[1].trim().split(",")[0].split('"')[2]), u.continuation = a.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents?.[1]?.continuationItemRenderer?.continuationEndpoint?.continuationCommand?.token; const d = { code: 200, msg: "", data: {data: l, next: JSON.stringify(u)}, id: "MusicSearchResultViewModel_search_result" }; return console.log(`unnext search result: ${JSON.stringify(d)}`), d } } catch (e) { const t = {code: -1, msg: e.toString()}; return console.log(`search result error: ${JSON.stringify(t)}`), t } } })(); //# sourceMappingURL=bundle.js.map