(() => { var __webpack_exports__ = {}; parseCodecs = e => { e = e.mimeType; if (!e) return {}; e = e.match(/(?[^/]+\/[^;]+)(?:;\s*codecs="?(?[^"]+))?/); if (!e) return {}; e = e.groups.codecs; if (!e) return {}; e = e.trim().replace(/,$/, "").split(",").map(e => e.trim()).filter(Boolean); let t = null, n = null; for (const i of e) { var o = i.split(".")[0]; ["avc1", "avc2", "avc3", "avc4", "vp9", "vp8", "hev1", "hev2", "h263", "h264", "mp4v", "hvc1", "av01", "theora"].includes(o) ? t = t || i : ["mp4a", "opus", "vorbis", "mp3", "aac", "ac-3", "ec-3", "eac3", "dtsc", "dtse", "dtsh", "dtsl"].includes(o) ? n = n || i : console.warn("WARNING: Unknown codec " + i) } return t || n ? {vcodec: t, acodec: n} : 2 === e.length ? {vcodec: e[0], acodec: e[1]} : {} }, request = async (e, t, i = null, s = {}, n) => (n && (t = t.replace("https://www.youtube.com", "http://127.0.0.1")), console.log("请求url:" + t), console.log("请求data:" + i), console.log("请求method:" + e), console.log("请求headers:" + JSON.stringify(s)), n ? fetch(t, { method: e, headers: s, body: i }).then(e => e.text()) : new Promise((n, o) => { AF.request(t, e, i, s, (e, t) => { t ? (console.log("请求失败: " + t), o(t)) : n(e) }) })), getStringBetween = (e, t, n, o = 0, i = 0) => { var s = e.indexOf(t), n = n ? e.indexOf(n, s) : e.length; return e.substring(s + t.length + i, n + o) }, getDecipherFunction = string => { const js = string.replace("var _yt_player={}", ""), top = getStringBetween(js, 'a=a.split("")', "};", 1, -28), beginningOfFunction = "var " + getStringBetween(top, 'a=a.split("")', "(", 10, 1).split(".")[0] + "=", side = getStringBetween(js, beginningOfFunction, "};", 2, -beginningOfFunction.length); return console.log("side: " + side), console.log("top: " + top), eval(side + top) }; const cache = {}; extractJSSignatureFunction = async (e, t) => { console.log("解析baseUrl: " + e); var n = "js:" + e; return cache[n] ? (console.log("从缓存中获取JSSignatureFunction: " + e), cache[n]) : (e = 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), (t = getDecipherFunction(e)) && (cache[n] = t), t) }, getUrlFromSignature = async (e, t, n) => { var t = await extractJSSignatureFunction(t, n), o = {}; for (const l of e.split("&")) { var [i, s] = l.split("="); o[decodeURIComponent(i)] = decodeURIComponent(s) } var [n, r, a] = [o.url, o.s, o.sp]; return console.log(e, n, r, a), n + `&${a}=` + t(r) }, detail = async (t, e) => { try { console.log("接受到解析请求: " + t); var n = await request("GET", t, 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"}, e), o = /var ytInitialPlayerResponse\s*=\s*({.*?});/, i = n.match(o); if (!i || !i.length) throw console.log("解释失败: 无法找到json"), new Error("JSON not found."); var s = JSON.parse(i[1]), r = s.videoDetails, a = (console.log("videoDetails: " + JSON.stringify(r)), []); for (const w of r.thumbnail.thumbnails) a.push({url: w.url, width: w.width + "", height: w.height + ""}); var l, c, u, d = [], h = "https://www.youtube.com" + JSON.parse(n.match(/set\(({.+?})\);/)[1]).PLAYER_JS_URL; for (l of [].concat(s.streamingData.formats).concat(s.streamingData.adaptiveFormats)) console.log("current format: " + JSON.stringify(l)), l.url || (l.url = await getUrlFromSignature(l.signatureCipher, h, e)), l.url && ({ vcodec: c, acodec: u } = parseCodecs(l), c) && u && d.push({ width: l.width + "", height: l.height + "", type: l.mimeType, quality: l.quality, itag: l.itag, fps: l.fps + "", bitrate: l.bitrate + "", url: l.url, ext: "mp4", vcodec: c, acodec: u, vbr: "0", abr: "0", container: "mp4_dash" }); if (o = /var ytInitialData\s*=\s*({.*?});/, !(i = n.match(o)) || !i.length) throw console.log("解析失败,无法找到 ytInitialData"), new Error("JSON not found."); var p, g = JSON.parse(i[1]), m = []; for (const x of g.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results) x.compactVideoRenderer && (p = x.compactVideoRenderer, console.log("推荐视频: " + JSON.stringify(p)), p.videoId) && m.push({ type: "gridVideoRenderer", videoId: p.videoId, title: p.title?.simpleText, thumbnails: p.thumbnail?.thumbnails, channelName: p.longBylineText?.runs?.[0]?.text, publishedTimeText: p.publishedTimeText?.simpleText, viewCountText: p.viewCountText?.simpleText, shortViewCountText: p.shortViewCountText?.simpleText, lengthText: p.lengthText?.simpleText }); var v = { code: 200, msg: "", data: { videoDetails: { isLiveContent: r.isLiveContent, title: r.title, thumbnails: a, description: r.shortDescription, lengthSeconds: r.lengthSeconds, viewCount: r.viewCount, keywords: r.keywords, author: r.author, channelID: r.channelId, recommendInfo: m, channelURL: "https://www.youtube.com/channel/" + r.channelId, videoId: r.videoId }, streamingData: {formats: d} }, id: "MusicDetailViewModel_detail_url" }; return console.log("解析结果: " + JSON.stringify(v)), v } catch (e) { t = {code: -1, msg: e.toString()}; return console.log("解析失败: " + JSON.stringify(t)), t } }, search = async (e, t, n) => { try { if (console.log("接受到搜索请求 keyword: " + e), console.log("接收到搜索请求 next: " + t), t) { var o = JSON.parse(t), i = o.key, s = { context: {client: {clientName: "WEB", clientVersion: "2.20240506.01.00"}}, continuation: o.continuation }, r = await request("POST", "https://www.youtube.com/youtubei/v1/search?key=" + i, JSON.stringify(s), {}, n), r = JSON.parse(r), a = []; for (const y of r.onResponseReceivedCommands[0].appendContinuationItemsAction.continuationItems[0].itemSectionRenderer.contents) { var l = y.videoRenderer; console.log("搜索结果: " + JSON.stringify(l)), l && l.videoId && a.push({ type: "videoWithContextRenderer", data: { videoId: l.videoId, title: l.title?.runs?.[0]?.text, thumbnails: l.thumbnail?.thumbnails, channelName: l.longBylineText?.runs?.[0]?.text, publishedTimeText: l.publishedTimeText?.simpleText, viewCountText: l.viewCountText?.simpleText, shortViewCountText: l.shortViewCountText?.simpleText, lengthText: l.lengthText?.simpleText } }) } var c = { code: 200, msg: "", data: { data: a, next: JSON.stringify({ key: o.key, continuation: r.onResponseReceivedCommands[0].appendContinuationItemsAction.continuationItems[1].continuationItemRenderer.continuationEndpoint.continuationCommand.token }) }, id: "MusicSearchResultViewModel_search_result" }; return console.log("携带next搜索结果成功: " + JSON.stringify(c)), c } var u = `https://www.youtube.com/results?q=${encodeURIComponent(e)}&sp=EgIQAQ%253D%253D`, d = await request("GET", u, null, {}, n), h = /var ytInitialData\s*=\s*({.*?});/, p = d.match(h); if (!p || !p.length) throw console.log("搜索失败:无法找到ytInitialData"), new Error("JSON not found."); var g, m = JSON.parse(p[1]), v = []; for (const T of m.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0].itemSectionRenderer.contents) T.videoRenderer && (g = T.videoRenderer, console.log("搜索结果: " + JSON.stringify(g)), g) && g.videoId && v.push({ type: "videoWithContextRenderer", data: { videoId: g.videoId, title: g.title?.runs?.[0]?.text, thumbnails: g.thumbnail?.thumbnails, channelName: g.longBylineText?.runs?.[0]?.text, publishedTimeText: g.publishedTimeText?.simpleText, viewCountText: g.viewCountText?.simpleText, shortViewCountText: g.shortViewCountText?.simpleText, lengthText: g.lengthText?.simpleText } }); var w = {}, x = (0 < d.split("innertubeApiKey").length && (w.key = d.split("innertubeApiKey")[1].trim().split(",")[0].split('"')[2]), w.continuation = m.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[1].continuationItemRenderer.continuationEndpoint.continuationCommand.token, { code: 200, msg: "", data: {data: v, next: JSON.stringify(w)}, id: "MusicSearchResultViewModel_search_result" }); return console.log("未携带next搜索结果成功: " + JSON.stringify(x)), x } catch (e) { t = {code: -1, msg: e.toString()}; return console.log("搜索失败: " + JSON.stringify(t)), t } } })();