|
@@ -1,9 +1,3 @@
|
|
|
-console.log('v2')
|
|
|
-
|
|
|
-printable = (platform) => {
|
|
|
- return platform === "WEB";
|
|
|
-}
|
|
|
-
|
|
|
parseCodecs = (format) => {
|
|
|
const mimeType = format['mimeType']
|
|
|
if (!mimeType) {
|
|
@@ -42,14 +36,12 @@ parseCodecs = (format) => {
|
|
|
if (!vcodec && !acodec) {
|
|
|
if (splitCodecs.length === 2) {
|
|
|
return {
|
|
|
- vcodec: splitCodecs[0],
|
|
|
- acodec: splitCodecs[1]
|
|
|
+ vcodec: splitCodecs[0], acodec: splitCodecs[1]
|
|
|
};
|
|
|
}
|
|
|
} else {
|
|
|
return {
|
|
|
- vcodec: vcodec,
|
|
|
- acodec: acodec
|
|
|
+ vcodec: vcodec, acodec: acodec
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -73,7 +65,7 @@ parseSetCookie = (headers) => {
|
|
|
const match = setCookie.match(regexp)
|
|
|
if (match && match.length === 2) {
|
|
|
const cookieValue = match[1]
|
|
|
- if (i != needCookieNames.length - 1) {
|
|
|
+ if (i !== needCookieNames.length - 1) {
|
|
|
result += `${cookieName}=${cookieValue}; `
|
|
|
} else {
|
|
|
result += `${cookieName}=${cookieValue}`
|
|
@@ -84,7 +76,7 @@ parseSetCookie = (headers) => {
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-request = async (method, url, data = null, headers = {}, platform) => {
|
|
|
+request = async (method, url, data = null, headers = {}, requestId, platform) => {
|
|
|
if (platform === "WEB") {
|
|
|
url = url.replace("https://www.youtube.com/", "http://16.162.163.175:80/");
|
|
|
url = url.replace("https://music.youtube.com/", "http://16.162.163.175:80/");
|
|
@@ -95,33 +87,28 @@ request = async (method, url, data = null, headers = {}, platform) => {
|
|
|
console.log(`request headers:${JSON.stringify((headers))}`)
|
|
|
if (platform === "WEB") {
|
|
|
const res = await fetch(url, {
|
|
|
- 'mode': 'cors',
|
|
|
- 'method': method,
|
|
|
- 'headers': headers,
|
|
|
- 'body': data
|
|
|
+ 'mode': 'cors', 'method': method, 'headers': headers, 'body': data
|
|
|
})
|
|
|
const resData = await res.text()
|
|
|
return Promise.resolve({
|
|
|
- 'data': resData,
|
|
|
- 'headers': res.headers
|
|
|
+ 'data': resData, 'headers': res.headers
|
|
|
});
|
|
|
}
|
|
|
return new Promise((resolve, reject) => {
|
|
|
- AF.request(url, method, data, headers, (data, headers, err) => {
|
|
|
+ AF.request(url, method, data, headers, requestId, (data, headers, err) => {
|
|
|
if (err) {
|
|
|
reject(err);
|
|
|
} else {
|
|
|
console.log(`response headers: ${headers}`);
|
|
|
resolve({
|
|
|
- 'data': data,
|
|
|
- 'headers': JSON.parse(headers)
|
|
|
+ 'data': data, 'headers': JSON.parse(headers)
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-detail = async (url, platform) => {
|
|
|
+detail = async (url, requestId, platform) => {
|
|
|
try {
|
|
|
const htmlResp = await request('GET', `${url}&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',
|
|
@@ -130,7 +117,7 @@ detail = async (url, platform) => {
|
|
|
'Sec-Fetch-Mode': 'navigate',
|
|
|
'Accept-Encoding': 'gzip, deflate, br',
|
|
|
'Cookie': 'PREF=hl=en&tz=UTC; SOCS=CAI'
|
|
|
- }, platform);
|
|
|
+ }, requestId, platform);
|
|
|
let {data: html, headers: htmlHeaders} = htmlResp;
|
|
|
|
|
|
let regex = /var ytInitialPlayerResponse\s*=\s*({.*?});/;
|
|
@@ -140,16 +127,12 @@ detail = async (url, platform) => {
|
|
|
throw new Error('JSON not found: ytInitialPlayerResponse');
|
|
|
}
|
|
|
const ytInitialPlayerResponse = JSON.parse(match[1]);
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(ytInitialPlayerResponse);
|
|
|
- }
|
|
|
+ console.log(ytInitialPlayerResponse);
|
|
|
const originVideoDetails = ytInitialPlayerResponse['videoDetails'];
|
|
|
const thumbnails = []
|
|
|
for (const item of originVideoDetails['thumbnail']['thumbnails']) {
|
|
|
thumbnails.push({
|
|
|
- 'url': item['url'],
|
|
|
- 'width': item['width'] + "",
|
|
|
- 'height': item['height'] + ""
|
|
|
+ 'url': item['url'], 'width': item['width'] + "", 'height': item['height'] + ""
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -161,14 +144,9 @@ detail = async (url, platform) => {
|
|
|
const apiResp = await request('POST', apiUrl, JSON.stringify({
|
|
|
"context": {
|
|
|
"client": {
|
|
|
- "clientName": "ANDROID",
|
|
|
- "hl": "en",
|
|
|
- "clientVersion": "18.49.37",
|
|
|
- "gl": "US"
|
|
|
+ "clientName": "ANDROID", "hl": "en", "clientVersion": "18.49.37", "gl": "US"
|
|
|
}
|
|
|
- },
|
|
|
- "videoId": url.replace('https://www.youtube.com/watch?v=', ''),
|
|
|
- "params": "CgIQBg"
|
|
|
+ }, "videoId": url.replace('https://www.youtube.com/watch?v=', ''), "params": "CgIQBg"
|
|
|
}), {
|
|
|
'Host': 'www.youtube.com',
|
|
|
'Connection': 'keep-alive',
|
|
@@ -176,7 +154,7 @@ detail = async (url, platform) => {
|
|
|
'Accept-Language': 'en-US,en',
|
|
|
'Cookie': parseSetCookie(htmlHeaders),
|
|
|
'Content-Type': 'application/json'
|
|
|
- }, platform);
|
|
|
+ }, requestId, platform);
|
|
|
let {data: apiData, _} = apiResp;
|
|
|
console.log(`android api result: ${JSON.stringify(apiResp)}`);
|
|
|
const res = JSON.parse(apiData);
|
|
@@ -191,25 +169,13 @@ detail = async (url, platform) => {
|
|
|
} catch (e) {
|
|
|
console.log(`can not found format android api error: ${e}`);
|
|
|
const ret = {
|
|
|
- "code": -1,
|
|
|
- "msg": e.toString()
|
|
|
+ "code": -1, "msg": e.toString()
|
|
|
}
|
|
|
console.log(`detail2 result error: ${JSON.stringify(ret)}`);
|
|
|
return ret;
|
|
|
}
|
|
|
console.log(`after android api, format size:${originFormats.length}`);
|
|
|
|
|
|
- // web
|
|
|
- // const currentFormats = [];
|
|
|
- // for (const format of ytInitialPlayerResponse["streamingData"]["formats"].concat(ytInitialPlayerResponse["streamingData"]["adaptiveFormats"])) {
|
|
|
- // if (format) {
|
|
|
- // format["from"] = "web"
|
|
|
- // currentFormats.push(format);
|
|
|
- // }
|
|
|
- // }
|
|
|
- // originFormats = originFormats.concat(currentFormats);
|
|
|
- // console.log(`after html, format size:${originFormats.length}`);
|
|
|
-
|
|
|
let audioUrl = ""
|
|
|
for (let format of originFormats) {
|
|
|
if (format["url"]) {
|
|
@@ -224,9 +190,7 @@ detail = async (url, platform) => {
|
|
|
const formats = [];
|
|
|
const qualities = [];
|
|
|
for (let format of originFormats) {
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(format);
|
|
|
- }
|
|
|
+ console.log(format);
|
|
|
if (format["height"] && parseInt(format["height"]) > 720) {
|
|
|
continue
|
|
|
}
|
|
@@ -290,9 +254,7 @@ detail = async (url, platform) => {
|
|
|
const recommendInfo = [];
|
|
|
if (ytInitialDataMatch && ytInitialDataMatch.length === 2) {
|
|
|
const ytInitialData = JSON.parse(ytInitialDataMatch[1]);
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(ytInitialData);
|
|
|
- }
|
|
|
+ console.log(ytInitialData);
|
|
|
for (const item of ytInitialData["contents"]?.["twoColumnWatchNextResults"]?.["secondaryResults"]?.["secondaryResults"]?.["results"] || []) {
|
|
|
if (item["compactVideoRenderer"]) {
|
|
|
const recommendVideo = item["compactVideoRenderer"];
|
|
@@ -331,22 +293,17 @@ detail = async (url, platform) => {
|
|
|
"videoId": originVideoDetails["videoId"]
|
|
|
}
|
|
|
const ret = {
|
|
|
- "code": 200,
|
|
|
- "msg": "",
|
|
|
- "data": {
|
|
|
- "videoDetails": videoDetails,
|
|
|
- "streamingData": {
|
|
|
+ "code": 200, "msg": "", "requestId": requestId, "data": {
|
|
|
+ "videoDetails": videoDetails, "streamingData": {
|
|
|
"formats": formats
|
|
|
}
|
|
|
- },
|
|
|
- "id": "MusicDetailViewModel_detail_url"
|
|
|
+ }, "id": "MusicDetailViewModel_detail_url"
|
|
|
}
|
|
|
console.log(`detail result: ${JSON.stringify(ret)}`);
|
|
|
return ret;
|
|
|
} catch (e) {
|
|
|
const ret = {
|
|
|
- "code": -1,
|
|
|
- "msg": e.toString()
|
|
|
+ "code": -1, "msg": e.toString(), "requestId": requestId,
|
|
|
}
|
|
|
console.log(`detail2 result error: ${JSON.stringify(ret)}`);
|
|
|
console.log(e);
|
|
@@ -354,7 +311,7 @@ detail = async (url, platform) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-search = async (keyword, next, platform) => {
|
|
|
+search = async (keyword, next, requestId, platform) => {
|
|
|
try {
|
|
|
console.log(`search keyword: ${keyword}`);
|
|
|
console.log(`search next: ${next}`);
|
|
@@ -364,25 +321,20 @@ search = async (keyword, next, platform) => {
|
|
|
const body = {
|
|
|
context: {
|
|
|
client: {
|
|
|
- clientName: "WEB",
|
|
|
- clientVersion: "2.20240506.01.00",
|
|
|
+ clientName: "WEB", clientVersion: "2.20240506.01.00",
|
|
|
},
|
|
|
- },
|
|
|
- continuation: nextObject["continuation"]
|
|
|
+ }, continuation: nextObject["continuation"]
|
|
|
};
|
|
|
- let res = await request('POST', `https://www.youtube.com/youtubei/v1/search?key=${key}`, JSON.stringify(body), {}, platform);
|
|
|
+ let res = await request('POST', `https://www.youtube.com/youtubei/v1/search?key=${key}`, JSON.stringify(body), {}, requestId, platform);
|
|
|
const {data, _} = res;
|
|
|
res = JSON.parse(data);
|
|
|
const videos = [];
|
|
|
for (const item of res["onResponseReceivedCommands"][0]["appendContinuationItemsAction"]["continuationItems"][0]["itemSectionRenderer"]["contents"]) {
|
|
|
const video = item["videoRenderer"];
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(video);
|
|
|
- }
|
|
|
+ console.log(video);
|
|
|
if (video && video["videoId"] && video["lengthText"]) {
|
|
|
videos.push({
|
|
|
- "type": "videoWithContextRenderer",
|
|
|
- "data": {
|
|
|
+ "type": "videoWithContextRenderer", "data": {
|
|
|
"videoId": video["videoId"],
|
|
|
"title": video["title"]?.["runs"]?.[0]?.["text"],
|
|
|
"thumbnails": video["thumbnail"]?.["thumbnails"],
|
|
@@ -396,23 +348,19 @@ search = async (keyword, next, platform) => {
|
|
|
}
|
|
|
}
|
|
|
const ret = {
|
|
|
- "code": 200,
|
|
|
- "msg": "",
|
|
|
- "data": {
|
|
|
- "data": videos,
|
|
|
- "next": JSON.stringify({
|
|
|
+ "code": 200, "msg": "", "requestId": requestId, "data": {
|
|
|
+ "data": videos, "next": JSON.stringify({
|
|
|
"key": nextObject["key"],
|
|
|
"continuation": res["onResponseReceivedCommands"]?.[0]?.["appendContinuationItemsAction"]?.["continuationItems"]?.[1]?.["continuationItemRenderer"]?.["continuationEndpoint"]?.["continuationCommand"]?.["token"],
|
|
|
}),
|
|
|
- },
|
|
|
- "id": "MusicSearchResultViewModel_search_result"
|
|
|
+ }, "id": "MusicSearchResultViewModel_search_result"
|
|
|
}
|
|
|
console.log(`[next] search result: ${JSON.stringify(ret)}`);
|
|
|
return ret;
|
|
|
} else {
|
|
|
let url = `https://www.youtube.com/results?q=${encodeURIComponent(keyword)}&sp=EgIQAQ%253D%253D`;
|
|
|
|
|
|
- const htmlRes = await request('GET', url, null, {}, platform);
|
|
|
+ const htmlRes = await request('GET', url, null, {}, requestId, platform);
|
|
|
const {data: html, _} = htmlRes;
|
|
|
|
|
|
let regex = /var ytInitialData\s*=\s*({.*?});/;
|
|
@@ -423,9 +371,7 @@ search = async (keyword, next, platform) => {
|
|
|
}
|
|
|
|
|
|
const ytInitialDataResp = JSON.parse(match[1]);
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(ytInitialDataResp);
|
|
|
- }
|
|
|
+ console.log(ytInitialDataResp);
|
|
|
const videos = [];
|
|
|
const contents = ytInitialDataResp["contents"]?.["twoColumnSearchResultsRenderer"]?.["primaryContents"]?.["sectionListRenderer"]?.["contents"] || []
|
|
|
for (const content of contents) {
|
|
@@ -434,13 +380,10 @@ search = async (keyword, next, platform) => {
|
|
|
for (const currentContent of currentContents) {
|
|
|
if (currentContent["videoRenderer"]) {
|
|
|
const video = currentContent["videoRenderer"];
|
|
|
- if (printable(platform)) {
|
|
|
- console.log(video);
|
|
|
- }
|
|
|
+ console.log(video);
|
|
|
if (video && video["videoId"] && video["lengthText"]) {
|
|
|
videos.push({
|
|
|
- "type": "videoWithContextRenderer",
|
|
|
- "data": {
|
|
|
+ "type": "videoWithContextRenderer", "data": {
|
|
|
"videoId": video["videoId"],
|
|
|
"title": video["title"]?.["runs"]?.[0]?.["text"],
|
|
|
"thumbnails": video["thumbnail"]?.["thumbnails"],
|
|
@@ -468,21 +411,16 @@ search = async (keyword, next, platform) => {
|
|
|
next["continuation"] = contents[contents.length - 1]?.["continuationItemRenderer"]?.["continuationEndpoint"]?.["continuationCommand"]?.["token"]
|
|
|
|
|
|
const ret = {
|
|
|
- "code": 200,
|
|
|
- "msg": "",
|
|
|
- "data": {
|
|
|
- "data": videos,
|
|
|
- "next": JSON.stringify(next),
|
|
|
- },
|
|
|
- "id": "MusicSearchResultViewModel_search_result"
|
|
|
+ "code": 200, "msg": "", "requestId": requestId, "data": {
|
|
|
+ "data": videos, "next": JSON.stringify(next),
|
|
|
+ }, "id": "MusicSearchResultViewModel_search_result"
|
|
|
}
|
|
|
console.log(`unnext search result: ${JSON.stringify(ret)}`);
|
|
|
return ret;
|
|
|
}
|
|
|
} catch (e) {
|
|
|
const ret = {
|
|
|
- "code": -1,
|
|
|
- "msg": e.toString()
|
|
|
+ "code": -1, "msg": e.toString(), "requestId": requestId,
|
|
|
}
|
|
|
console.log(`search result error: ${JSON.stringify(ret)}`);
|
|
|
return ret;
|