vrchat-youtube-search-api/VRCYoutubeSearch.js
2024-06-17 16:24:26 -07:00

122 lines
3.4 KiB
JavaScript

import { searchYouTubeVideos, continueYouTubeVideoSearch, getYouTubePlaylist, continueYouTubePlaylist, getTrending } from "./youtube.js";
import { putVrcUrl } from "./vrcurl.js";
import { makeImageSheetVrcUrl } from "./imagesheet.js";
var cache = {};
export async function cachedVRCYoutubeSearch(pool, query, options) {
var key = JSON.stringify([pool, query, options]);
if (!cache[key]) {
cache[key] = VRCYoutubeSearch(pool, query, options);
setTimeout(() => {
delete cache[key];
}, 1000*60*10); // 10 mins
}
return await cache[key];
}
async function VRCYoutubeSearch(pool, query, options = {}) {
console.log("search:", JSON.stringify(query));
var data = {results: []};
if (typeof query == "object") {
switch (query.type) {
case "trending":
var {videos, tabs} = await getTrending(query.bp);
data.tabs = [];
for (let tab of tabs) {
data.tabs.push({
name: tab.name,
vrcurl: await putVrcUrl(pool, {type: "trending", bp: tab.bp, options})
});
}
break;
case "continuation":
//var {videos, continuationData} = await [query.for == "playlist" ? continueYouTubePlaylist : continueYouTubeVideoSearch](query.continuationData);
if (query.for == "playlist") {
var {videos, continuationData} = await continueYouTubePlaylist(query.continuationData);
} else {
var {videos, continuationData} = await continueYouTubeVideoSearch(query.continuationData);
}
break;
}
} else {
var playlistId = query.match(/list=(PL[a-zA-Z0-9-_]{32})/)?.[1];
if (playlistId) console.log("playlistId:", playlistId);
var {videos, continuationData} = playlistId ? await getYouTubePlaylist(playlistId) : await searchYouTubeVideos(query);
}
var images = [];
if (options.thumbnails) {
videos.forEach(video => {
video.thumbnail = playlistId ? {
url: `https://i.ytimg.com/vi/${video.id}/default.jpg`,
width: 120,
height: 90
} : {
url: `https://i.ytimg.com/vi/${video.id}/mqdefault.jpg`,
width: 320,
height: 180
};
images.push(video.thumbnail);
});
}
if (options.icons) {
let iconUrls = new Set();
videos.forEach(video => video.channel.iconUrl && iconUrls.add(video.channel.iconUrl));
iconUrls.forEach(url => images.push({
width: 68,//todo pass from yt data not hardcode
height: 68,
url
}));
}
if (images.length) {
try {
var {vrcurl: imagesheet_vrcurl} = await makeImageSheetVrcUrl(pool, images);
data.imagesheet_vrcurl = imagesheet_vrcurl;
} catch (error) {
console.error(error.stack);
}
}
for (let video of videos) {
video.vrcurl = await putVrcUrl(pool, {type: "redirect", url: `https://www.youtube.com/watch?v=${video.id}`});
let thumbnail = images.find(image => image.url == video.thumbnail.url);
video.thumbnail = thumbnail ? {
x: thumbnail?.x,
y: thumbnail?.y,
width: thumbnail?.width,
height: thumbnail?.height
} : undefined;
let icon = images.find(image => image.url == video.channel.iconUrl);
video.channel.icon = icon ? {
x: icon?.x,
y: icon?.y,
width: icon?.width,
height: icon?.height
} : undefined;
if (options.captions) {
video.captions_vrcurl = await putVrcUrl(pool, {type: "captions", videoId: video.id});
}
delete video.channel.iconUrl;
data.results.push(video);
}
if (continuationData) data.nextpage_vrcurl = await putVrcUrl(pool, {
type: "continuation",
for: query.for || (playlistId ? "playlist" : "search"),
continuationData,
options
});
return data;
}