Compare commits
No commits in common. "master" and "wip" have entirely different histories.
18
README.md
18
README.md
@ -13,14 +13,13 @@ Get YouTube videos for a search query.
|
|||||||
### Required query parameters
|
### Required query parameters
|
||||||
|
|
||||||
- `pool`: id of the VRCUrl pool, only letters numbers hyphens or underscores, optionally followed by an integer for pool size.
|
- `pool`: id of the VRCUrl pool, only letters numbers hyphens or underscores, optionally followed by an integer for pool size.
|
||||||
- `input`: youtube search query. All chars up to and including this exact unicode char `→` are ignored, and then whitespace is trimmed. THIS MUST BE THE LAST QUERY PARAMETER AS ALL CHARS AFTER IT ARE CAPTURED VERBATIM (so you can type & etc without encoding). If this contains a url with a playlist ID, playlist results will be loaded instead (which is a bit different, up to 100 results and no descriptions).
|
- `input`: youtube search query. All chars up to and including this exact unicode char `→` are ignored, and then whitespace is trimmed. THIS MUST BE THE LAST QUERY PARAMETER AS ALL CHARS AFTER IT ARE CAPTURED VERBATIM (so you can type & etc without encoding)
|
||||||
|
|
||||||
### Optional query parameters
|
### Optional query parameters
|
||||||
|
|
||||||
- `thumbnails`: set to `1`, `true`, `yes`, `on` or whatever to load thumbnails
|
- `thumbnails`: set to `1`, `true`, `yes`, `on` or whatever to load thumbnails
|
||||||
- `icons`: set to `1`, `true`, `yes`, `on` or whatever to load channel icons
|
- `icons`: set to `1`, `true`, `yes`, `on` or whatever to load channel icons
|
||||||
- `mode`: If set to `latestontop` will search without filter to include the "Latest from ..." section (if it exists). Otherwise it uses search filter for Videos only sorted by Relevance.
|
- `captions`: set to `1`, `true`, `yes`, `on` or whatever if you need access to closed captioning data
|
||||||
- `bp`: Custom YouTube search filter. Go to youtube search site and set some filters and you will see the corresponding `bp` value in the URL. Overrides `mode` option. Use at your own risk (experimental).
|
|
||||||
|
|
||||||
### Example URL
|
### Example URL
|
||||||
|
|
||||||
@ -33,11 +32,11 @@ https://api.u2b.cx/search?pool=example10000&input= Type YouTube search query h
|
|||||||
JSON object:
|
JSON object:
|
||||||
|
|
||||||
- `results`: Array of Object
|
- `results`: Array of Object
|
||||||
- `vrcurl`: (integer) index of VRCUrl that will redirect to the youtube url, or serve JSON with captions if used with string loader.
|
- `vrcurl`: (integer) index of VRCUrl that will redirect to the youtube url
|
||||||
- `live`: (boolean) whether it's a live stream
|
- `live`: (boolean) whether it's a live stream
|
||||||
- `title`: (string) i.e. `"Nyan Cat! [Official]"`
|
- `title`: (string) i.e. `"Nyan Cat! [Official]"`
|
||||||
- `id`: (string) YouTube video id i.e. `"2yJgwwDcgV8"`
|
- `id`: (string) YouTube video id i.e. `"2yJgwwDcgV8"`
|
||||||
- `description`?: (string) short truncated description snippet i.e. `"http://nyan.cat/ Original song : http://momolabo.lolipop.jp/nyancatsong/Nyan/"` (playlist results don't have this)
|
- `description`: (string) short truncated description snippet i.e. `"http://nyan.cat/ Original song : http://momolabo.lolipop.jp/nyancatsong/Nyan/"`
|
||||||
- `lengthText`?: (string) i.e. `"3:37"`
|
- `lengthText`?: (string) i.e. `"3:37"`
|
||||||
- `longLengthText`?: (string) i.e. `"3 minutes, 37 seconds"`
|
- `longLengthText`?: (string) i.e. `"3 minutes, 37 seconds"`
|
||||||
- `viewCountText`?: (string) i.e. `"2,552,243 views"` or `"575 watching"` for live streams (playlist results don't have this)
|
- `viewCountText`?: (string) i.e. `"2,552,243 views"` or `"575 watching"` for live streams (playlist results don't have this)
|
||||||
@ -56,6 +55,7 @@ JSON object:
|
|||||||
- `y`: (integer) px from top
|
- `y`: (integer) px from top
|
||||||
- `width`: (integer)
|
- `width`: (integer)
|
||||||
- `height`: (integer)
|
- `height`: (integer)
|
||||||
|
- `captions_vrcurl`?: (integer) index of vrcurl to get the caption data json
|
||||||
- `imagesheet_vrcurl`?: (integer) index of the vrcurl for the collage of thumbnails and/or icons
|
- `imagesheet_vrcurl`?: (integer) index of the vrcurl for the collage of thumbnails and/or icons
|
||||||
- `nextpage_vrcurl`: (integer) index of the vrcurl that will serve the JSON for the next page of results
|
- `nextpage_vrcurl`: (integer) index of the vrcurl that will serve the JSON for the next page of results
|
||||||
|
|
||||||
@ -73,11 +73,11 @@ Gets Trending YouTube videos. Identical to `/search` but without `input` paramet
|
|||||||
- `{pool}`: must be same as pool param in search endpoint.
|
- `{pool}`: must be same as pool param in search endpoint.
|
||||||
- `{index}`: vrcurl index number
|
- `{index}`: vrcurl index number
|
||||||
|
|
||||||
Response may be 302 redirect to youtube url, `image/png` for imagesheet, `application/json` for next page (see response format above) or trending tab or video json data (see below).
|
Response may be 302 redirect to youtube url, `image/png` for imagesheet, `application/json` for next page (see response format above) or trending tab or caption data (below).
|
||||||
|
|
||||||
### Video metadata JSON format
|
### Caption JSON format
|
||||||
|
|
||||||
- `captions`: Array of Object
|
- Array of Object
|
||||||
- `name`: (string) caption track name like "English" or "English (auto-generated)"
|
- `name`: (string) caption track name like "English" or "English (auto-generated)"
|
||||||
- `id`: (string) id like `.en` or `a.en`
|
- `id`: (string) id like `.en` or `a.en`
|
||||||
- `lines`: Array of Object
|
- `lines`: Array of Object
|
||||||
@ -108,4 +108,4 @@ All resources (youtube urls etc) referenced in the search results will be substi
|
|||||||
|
|
||||||
Video thumbnails and channel icons are collated together into one image and served at a VRCUrl to be loaded by VRCImageDownloader.
|
Video thumbnails and channel icons are collated together into one image and served at a VRCUrl to be loaded by VRCImageDownloader.
|
||||||
|
|
||||||
Use the x, y, width and height values from the json to crop the image from the sheet. Do not make any assumptions about these values as the server could arrange the images wherever it wants.
|
Use the x, y, width and height values from the json to crop the image from the sheet.
|
@ -1,36 +1,36 @@
|
|||||||
import { searchYouTubeVideos, continueYouTubeVideoSearch, getYouTubePlaylist, continueYouTubePlaylist, getTrending } from "./youtube.js";
|
import { searchYouTubeVideos, continueYouTubeVideoSearch, getYouTubePlaylist, continueYouTubePlaylist, getTrending } from "./youtube.js";
|
||||||
import { putVrcUrl } from "./vrcurl.js";
|
import { putVrcUrl } from "./vrcurl.js";
|
||||||
import { createImageSheet } from "./imagesheet.js";
|
import { makeImageSheetVrcUrl } from "./imagesheet.js";
|
||||||
|
|
||||||
var cache = {};
|
var cache = {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function cachedVRCYoutubeSearch(pool, query, options) {
|
export async function cachedVRCYoutubeSearch(pool, query, options) {
|
||||||
var key = JSON.stringify([pool, query, options]);
|
var key = JSON.stringify([pool, query, options]);
|
||||||
if (!cache[key]) {
|
if (!cache[key]) {
|
||||||
cache[key] = VRCYoutubeSearch(pool, query, options, key);
|
cache[key] = VRCYoutubeSearch(pool, query, options);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
delete cache[key];
|
delete cache[key];
|
||||||
}, 1000*60*10); // 10 mins
|
}, 1000*60*10); // 10 mins
|
||||||
}
|
}
|
||||||
return (await cache[key])?.response;
|
return await cache[key];
|
||||||
}
|
|
||||||
|
|
||||||
export async function getImageSheet(key) {
|
|
||||||
return await (await cache[key])?.imagesheet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function VRCYoutubeSearch(pool, query, options = {}, key) {
|
|
||||||
console.log("search", pool, JSON.stringify(query), JSON.stringify(options));
|
|
||||||
var response = {results: []};
|
async function VRCYoutubeSearch(pool, query, options = {}) {
|
||||||
|
console.log("search:", JSON.stringify(query));
|
||||||
|
var data = {results: []};
|
||||||
|
|
||||||
if (typeof query == "object") {
|
if (typeof query == "object") {
|
||||||
switch (query.type) {
|
switch (query.type) {
|
||||||
case "trending":
|
case "trending":
|
||||||
var {videos, tabs} = await getTrending(query.bp);
|
var {videos, tabs} = await getTrending(query.bp);
|
||||||
response.tabs = [];
|
data.tabs = [];
|
||||||
for (let tab of tabs) {
|
for (let tab of tabs) {
|
||||||
response.tabs.push({
|
data.tabs.push({
|
||||||
name: tab.name,
|
name: tab.name,
|
||||||
vrcurl: await putVrcUrl(pool, {type: "trending", bp: tab.bp, options})
|
vrcurl: await putVrcUrl(pool, {type: "trending", bp: tab.bp, options})
|
||||||
});
|
});
|
||||||
@ -48,28 +48,22 @@ async function VRCYoutubeSearch(pool, query, options = {}, key) {
|
|||||||
} else {
|
} else {
|
||||||
var playlistId = query.match(/list=(PL[a-zA-Z0-9-_]{32})/)?.[1];
|
var playlistId = query.match(/list=(PL[a-zA-Z0-9-_]{32})/)?.[1];
|
||||||
if (playlistId) console.log("playlistId:", playlistId);
|
if (playlistId) console.log("playlistId:", playlistId);
|
||||||
var {videos, continuationData} = playlistId ? await getYouTubePlaylist(playlistId) : await searchYouTubeVideos(query, options.bp || (options.mode == "latestontop" ? null : undefined));
|
var {videos, continuationData} = playlistId ? await getYouTubePlaylist(playlistId) : await searchYouTubeVideos(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
var images = [];
|
var images = [];
|
||||||
|
|
||||||
if (options.thumbnails) {
|
if (options.thumbnails) {
|
||||||
videos.forEach(video => {
|
videos.forEach(video => {
|
||||||
if (playlistId) video.thumbnail = {
|
video.thumbnail = playlistId ? {
|
||||||
url: `https://i.ytimg.com/vi/${video.id}/default.jpg`,
|
url: `https://i.ytimg.com/vi/${video.id}/default.jpg`,
|
||||||
width: 120,
|
width: 120,
|
||||||
height: 90
|
height: 90
|
||||||
|
} : {
|
||||||
|
url: `https://i.ytimg.com/vi/${video.id}/mqdefault.jpg`,
|
||||||
|
width: 320,
|
||||||
|
height: 180
|
||||||
};
|
};
|
||||||
else {
|
|
||||||
video.thumbnail ||= {
|
|
||||||
url: `https://i.ytimg.com/vi/${video.id}/mqdefault.jpg`,
|
|
||||||
width: 320,
|
|
||||||
height: 180
|
|
||||||
};
|
|
||||||
console.debug(video.thumbnail);
|
|
||||||
video.thumbnail.width = 360;
|
|
||||||
video.thumbnail.height = 202;
|
|
||||||
}
|
|
||||||
images.push(video.thumbnail);
|
images.push(video.thumbnail);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -86,15 +80,15 @@ async function VRCYoutubeSearch(pool, query, options = {}, key) {
|
|||||||
|
|
||||||
if (images.length) {
|
if (images.length) {
|
||||||
try {
|
try {
|
||||||
response.imagesheet_vrcurl = await putVrcUrl(pool, {type: "imagesheet", key});
|
var {vrcurl: imagesheet_vrcurl} = await makeImageSheetVrcUrl(pool, images);
|
||||||
var imagesheet = createImageSheet(images, !playlistId && !options.icons);
|
data.imagesheet_vrcurl = imagesheet_vrcurl;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let video of videos) {
|
for (let video of videos) {
|
||||||
video.vrcurl = await putVrcUrl(pool, {type: "video", id: video.id});
|
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);
|
let thumbnail = images.find(image => image.url == video.thumbnail.url);
|
||||||
video.thumbnail = thumbnail ? {
|
video.thumbnail = thumbnail ? {
|
||||||
x: thumbnail?.x,
|
x: thumbnail?.x,
|
||||||
@ -113,15 +107,15 @@ async function VRCYoutubeSearch(pool, query, options = {}, key) {
|
|||||||
video.captions_vrcurl = await putVrcUrl(pool, {type: "captions", videoId: video.id});
|
video.captions_vrcurl = await putVrcUrl(pool, {type: "captions", videoId: video.id});
|
||||||
}
|
}
|
||||||
delete video.channel.iconUrl;
|
delete video.channel.iconUrl;
|
||||||
response.results.push(video);
|
data.results.push(video);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (continuationData) response.nextpage_vrcurl = await putVrcUrl(pool, {
|
if (continuationData) data.nextpage_vrcurl = await putVrcUrl(pool, {
|
||||||
type: "continuation",
|
type: "continuation",
|
||||||
for: query.for || (playlistId ? "playlist" : "search"),
|
for: query.for || (playlistId ? "playlist" : "search"),
|
||||||
continuationData,
|
continuationData,
|
||||||
options
|
options
|
||||||
});
|
});
|
||||||
|
|
||||||
return {response, imagesheet};
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,15 @@
|
|||||||
import { createCanvas, loadImage } from 'canvas';
|
import { createCanvas, loadImage } from 'canvas';
|
||||||
import potpack from 'potpack';
|
import potpack from 'potpack';
|
||||||
|
import { putVrcUrl } from './vrcurl.js';
|
||||||
|
|
||||||
export async function createImageSheet(images /*[{width, height, url}]*/, legacyMode) {
|
var store = {};
|
||||||
|
|
||||||
|
async function createImageSheet(images /*[{width, height, url}]*/) {
|
||||||
images.forEach(image => {
|
images.forEach(image => {
|
||||||
image.w = image.width;
|
image.w = image.width;
|
||||||
image.h = image.height;
|
image.h = image.height;
|
||||||
});
|
});
|
||||||
if (legacyMode) {
|
var {w, h, fill} = potpack(images);
|
||||||
images.forEach((image, index) => {
|
|
||||||
image.x = index % 5 * 360;
|
|
||||||
image.y = Math.floor(index / 5) * 202;
|
|
||||||
});
|
|
||||||
var w = Math.min(images.length, 5) * 360;
|
|
||||||
var h = images.at(-1).y + 202;
|
|
||||||
} else {
|
|
||||||
var {w, h, fill} = potpack(images);
|
|
||||||
}
|
|
||||||
if (w > 2048) {
|
if (w > 2048) {
|
||||||
console.warn("Imagesheet exceeded max width");
|
console.warn("Imagesheet exceeded max width");
|
||||||
w = 2048;
|
w = 2048;
|
||||||
@ -29,14 +23,36 @@ export async function createImageSheet(images /*[{width, height, url}]*/, legacy
|
|||||||
|
|
||||||
await Promise.all(images.map(({x, y, w, h, url}) => (async function(){
|
await Promise.all(images.map(({x, y, w, h, url}) => (async function(){
|
||||||
if (!url) return;
|
if (!url) return;
|
||||||
try {
|
var image = await loadImage(url);
|
||||||
var image = await loadImage(url);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("failed to load image", url, error.message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.drawImage(image, x, y, w, h);
|
ctx.drawImage(image, x, y, w, h);
|
||||||
})().catch(error => console.error("imageload", error.stack))));
|
})().catch(error => console.error(error.stack))));
|
||||||
|
|
||||||
return canvas.toBuffer("image/png");
|
return {
|
||||||
|
imagesheet: canvas.toBuffer("image/png"),
|
||||||
|
images
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function makeImageSheetVrcUrl(pool, images) {
|
||||||
|
var num = await putVrcUrl(pool, {type: "imagesheet"});
|
||||||
|
var key = `${pool}:${num}`;
|
||||||
|
var promise = createImageSheet(images);
|
||||||
|
store[key] = promise;
|
||||||
|
promise.then(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (store[key] === promise) delete store[key];
|
||||||
|
}, 1000*60*10); // 10 mins;
|
||||||
|
});
|
||||||
|
promise.catch(error => {
|
||||||
|
console.error(error.stack);
|
||||||
|
});
|
||||||
|
var {thumbnails, icons} = await promise;
|
||||||
|
return {
|
||||||
|
vrcurl: num,
|
||||||
|
thumbnails, icons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getImageSheet(pool, num) {
|
||||||
|
return (await store[`${pool}:${num}`])?.imagesheet;
|
||||||
|
}
|
53
index.js
53
index.js
@ -1,16 +1,14 @@
|
|||||||
if (process.env.D!="BUG") console.debug = () => {};
|
if (process.env.D!="BUG") console.debug = () => {};
|
||||||
else console.debug(process.env);
|
|
||||||
import "./util.js";
|
import "./util.js";
|
||||||
import Koa from "koa";
|
import Koa from "koa";
|
||||||
import Router from "@koa/router";
|
import Router from "@koa/router";
|
||||||
import send from "koa-send";
|
import send from "koa-send";
|
||||||
import qs from "qs";
|
import { cachedVRCYoutubeSearch } from "./VRCYoutubeSearch.js"
|
||||||
import { cachedVRCYoutubeSearch, getImageSheet } from "./VRCYoutubeSearch.js"
|
import { getImageSheet } from "./imagesheet.js";
|
||||||
import { resolveVrcUrl } from "./vrcurl.js";
|
import { resolveVrcUrl } from "./vrcurl.js";
|
||||||
import { getVideoCaptionsCached } from "./youtube-captions.js";
|
import { getVideoCaptionsCached } from "./youtube-captions.js";
|
||||||
import { stringToBoolean } from "./util.js";
|
import { stringToBoolean } from "./util.js";
|
||||||
import { readFileSync } from "fs";
|
import shorturlmap from "./shorturlmap.json" assert { type: "json" };
|
||||||
var shorturlmap = JSON.parse(readFileSync("./shorturlmap.json", "utf8"));
|
|
||||||
|
|
||||||
var app = new Koa();
|
var app = new Koa();
|
||||||
var router = new Router();
|
var router = new Router();
|
||||||
@ -18,34 +16,30 @@ var router = new Router();
|
|||||||
|
|
||||||
router.get(["/search", "/trending"], async ctx => {
|
router.get(["/search", "/trending"], async ctx => {
|
||||||
if (ctx.path == "/trending") {
|
if (ctx.path == "/trending") {
|
||||||
var input = {"type":"trending"};
|
var query = {"type":"trending"};
|
||||||
} else {
|
} else {
|
||||||
var input = ctx.querystring.match(/[?&]input=(.*)/i)?.[1];
|
var query = ctx.querystring.match(/[?&]input=(.*)/i)?.[1];
|
||||||
if (!input) {
|
if (!query) {
|
||||||
ctx.status = 400;
|
ctx.status = 400;
|
||||||
ctx.body = "missing search query";
|
ctx.body = "missing search query";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
input = decodeURIComponent(input).replace(/^.*→/, '').replaceAll("\u200b", '').trim();
|
query = decodeURIComponent(query).replace(/^.*→/, '').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pqs = qs.parse(ctx.querystring, {duplicates: 'first'});
|
if (!ctx.query.pool || !/^[a-z-_]+\d*$/.test(ctx.query.pool)) {
|
||||||
|
|
||||||
if (!pqs.pool || /[^a-z-_0-9]/.test(pqs.pool)) {
|
|
||||||
ctx.status = 400;
|
ctx.status = 400;
|
||||||
ctx.body = "invalid pool";
|
ctx.body = "invalid pool";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
thumbnails: stringToBoolean(pqs.thumbnails),
|
thumbnails: stringToBoolean(ctx.query.thumbnails),
|
||||||
icons: stringToBoolean(pqs.icons),
|
icons: stringToBoolean(ctx.query.icons),
|
||||||
captions: stringToBoolean(pqs.captions),
|
captions: stringToBoolean(ctx.query.captions)
|
||||||
mode: pqs.mode,
|
|
||||||
bp: pqs.bp
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.body = await cachedVRCYoutubeSearch(pqs.pool, input, options);
|
ctx.body = await cachedVRCYoutubeSearch(ctx.query.pool, query, options);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -59,15 +53,8 @@ router.get("/vrcurl/:pool/:num", async ctx => {
|
|||||||
case "redirect":
|
case "redirect":
|
||||||
ctx.redirect(dest.url);
|
ctx.redirect(dest.url);
|
||||||
break;
|
break;
|
||||||
case "video":
|
|
||||||
if (ctx.get("User-Agent").includes("UnityWebRequest")) {
|
|
||||||
ctx.body = {captions: await getVideoCaptionsCached(dest.id)};
|
|
||||||
} else {
|
|
||||||
ctx.redirect(`https://www.youtube.com/watch?v=${dest.id}`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "imagesheet":
|
case "imagesheet":
|
||||||
let buf = await getImageSheet(dest.key);
|
let buf = await getImageSheet(ctx.params.pool, ctx.params.num);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
ctx.status = 404;
|
ctx.status = 404;
|
||||||
return;
|
return;
|
||||||
@ -107,18 +94,6 @@ router.get("/", ctx => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
app.use(async (ctx, next) => {
|
|
||||||
try {
|
|
||||||
await next();
|
|
||||||
} catch (error) {
|
|
||||||
console.error(ctx.url, error.stack);
|
|
||||||
ctx.status = 500;
|
|
||||||
ctx.type = "text";
|
|
||||||
ctx.body = error.stack;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// short urls to work around https://feedback.vrchat.com/udon/p/vrcurlinputfield-incorrect-focus-issue-on-quest
|
// short urls to work around https://feedback.vrchat.com/udon/p/vrcurlinputfield-incorrect-focus-issue-on-quest
|
||||||
app.use(async (ctx, next) => {
|
app.use(async (ctx, next) => {
|
||||||
var subdomain = ctx.hostname.match(/(.*).u2b.cx$/i)?.[1];
|
var subdomain = ctx.hostname.match(/(.*).u2b.cx$/i)?.[1];
|
||||||
@ -154,4 +129,4 @@ app.use(async (ctx, next) => {
|
|||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
app.use(router.allowedMethods());
|
app.use(router.allowedMethods());
|
||||||
|
|
||||||
app.listen(process.env.PORT || 8142, process.env.ADDRESS);
|
app.listen(process.env.PORT || 8142, process.env.ADDRESS);
|
457
package-lock.json
generated
457
package-lock.json
generated
@ -4,18 +4,15 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "vrchat-youtube-search-api",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@keyv/sqlite": "^3.6.6",
|
"@keyv/sqlite": "^3.6.6",
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"canvas": "^2.11.2",
|
"canvas": "^2.11.2",
|
||||||
"fast-xml-parser": "^4.3.4",
|
"fast-xml-parser": "^4.3.4",
|
||||||
"got": "^14.4.1",
|
|
||||||
"keyv": "^4.5.4",
|
"keyv": "^4.5.4",
|
||||||
"koa": "^2.14.2",
|
"koa": "^2.14.2",
|
||||||
"koa-send": "^5.0.1",
|
"koa-send": "^5.0.1",
|
||||||
"potpack": "^2.0.0",
|
"potpack": "^2.0.0"
|
||||||
"qs": "^6.12.2"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
@ -138,33 +135,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sec-ant/readable-stream": {
|
|
||||||
"version": "0.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
|
|
||||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="
|
|
||||||
},
|
|
||||||
"node_modules/@sindresorhus/is": {
|
|
||||||
"version": "6.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-6.3.1.tgz",
|
|
||||||
"integrity": "sha512-FX4MfcifwJyFOI2lPoX7PQxCqx8BG1HCho7WdiXwpEQx1Ycij0JxkfYtGK7yqNScrZGSlt6RE6sw8QYoH7eKnQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@szmarczak/http-timer": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
|
|
||||||
"dependencies": {
|
|
||||||
"defer-to-connect": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@tootallnate/once": {
|
"node_modules/@tootallnate/once": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
|
||||||
@ -174,11 +144,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-cache-semantics": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
|
|
||||||
},
|
|
||||||
"node_modules/abbrev": {
|
"node_modules/abbrev": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
@ -312,75 +277,6 @@
|
|||||||
"node": ">= 6.0.0"
|
"node": ">= 6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cacheable-lookup": {
|
|
||||||
"version": "7.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
|
|
||||||
"integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cacheable-request": {
|
|
||||||
"version": "12.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-12.0.1.tgz",
|
|
||||||
"integrity": "sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/http-cache-semantics": "^4.0.4",
|
|
||||||
"get-stream": "^9.0.1",
|
|
||||||
"http-cache-semantics": "^4.1.1",
|
|
||||||
"keyv": "^4.5.4",
|
|
||||||
"mimic-response": "^4.0.0",
|
|
||||||
"normalize-url": "^8.0.1",
|
|
||||||
"responselike": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cacheable-request/node_modules/get-stream": {
|
|
||||||
"version": "9.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
|
|
||||||
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sec-ant/readable-stream": "^0.4.1",
|
|
||||||
"is-stream": "^4.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cacheable-request/node_modules/mimic-response": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/call-bind": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"set-function-length": "^1.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/canvas": {
|
"node_modules/canvas": {
|
||||||
"version": "2.11.2",
|
"version": "2.11.2",
|
||||||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
|
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz",
|
||||||
@ -502,30 +398,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||||
"integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw=="
|
"integrity": "sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw=="
|
||||||
},
|
},
|
||||||
"node_modules/defer-to-connect": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/define-data-property": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"gopd": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
@ -610,34 +482,15 @@
|
|||||||
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/es-define-property": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"get-intrinsic": "^1.2.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es-errors": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/escape-html": {
|
"node_modules/escape-html": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
||||||
},
|
},
|
||||||
"node_modules/fast-xml-parser": {
|
"node_modules/fast-xml-parser": {
|
||||||
"version": "4.5.0",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.3.4.tgz",
|
||||||
"integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==",
|
"integrity": "sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -648,7 +501,6 @@
|
|||||||
"url": "https://paypal.me/naturalintelligence"
|
"url": "https://paypal.me/naturalintelligence"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"strnum": "^1.0.5"
|
"strnum": "^1.0.5"
|
||||||
},
|
},
|
||||||
@ -656,14 +508,6 @@
|
|||||||
"fxparser": "src/cli/cli.js"
|
"fxparser": "src/cli/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/form-data-encoder": {
|
|
||||||
"version": "4.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz",
|
|
||||||
"integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fresh": {
|
"node_modules/fresh": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
@ -688,14 +532,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||||
},
|
},
|
||||||
"node_modules/function-bind": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gauge": {
|
"node_modules/gauge": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
|
||||||
@ -715,35 +551,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/get-intrinsic": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"has-proto": "^1.0.1",
|
|
||||||
"has-symbols": "^1.0.3",
|
|
||||||
"hasown": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/get-stream": {
|
|
||||||
"version": "8.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
|
||||||
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/glob": {
|
"node_modules/glob": {
|
||||||
"version": "7.2.3",
|
"version": "7.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||||
@ -763,95 +570,12 @@
|
|||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/gopd": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
|
||||||
"dependencies": {
|
|
||||||
"get-intrinsic": "^1.1.3"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/got": {
|
|
||||||
"version": "14.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/got/-/got-14.4.1.tgz",
|
|
||||||
"integrity": "sha512-IvDJbJBUeexX74xNQuMIVgCRRuNOm5wuK+OC3Dc2pnSoh1AOmgc7JVj7WC+cJ4u0aPcO9KZ2frTXcqK4W/5qTQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sindresorhus/is": "^6.3.1",
|
|
||||||
"@szmarczak/http-timer": "^5.0.1",
|
|
||||||
"cacheable-lookup": "^7.0.0",
|
|
||||||
"cacheable-request": "^12.0.1",
|
|
||||||
"decompress-response": "^6.0.0",
|
|
||||||
"form-data-encoder": "^4.0.2",
|
|
||||||
"get-stream": "^8.0.1",
|
|
||||||
"http2-wrapper": "^2.2.1",
|
|
||||||
"lowercase-keys": "^3.0.0",
|
|
||||||
"p-cancelable": "^4.0.1",
|
|
||||||
"responselike": "^3.0.0",
|
|
||||||
"type-fest": "^4.19.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=20"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/got?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/got/node_modules/decompress-response": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"mimic-response": "^3.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/got/node_modules/mimic-response": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/graceful-fs": {
|
"node_modules/graceful-fs": {
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/has-property-descriptors": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-proto": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-symbols": {
|
"node_modules/has-symbols": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||||
@ -882,17 +606,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||||
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
|
||||||
},
|
},
|
||||||
"node_modules/hasown": {
|
|
||||||
"version": "2.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
|
||||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"function-bind": "^1.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/http-assert": {
|
"node_modules/http-assert": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.5.0.tgz",
|
||||||
@ -908,7 +621,8 @@
|
|||||||
"node_modules/http-cache-semantics": {
|
"node_modules/http-cache-semantics": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
||||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
|
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/http-errors": {
|
"node_modules/http-errors": {
|
||||||
"version": "1.8.1",
|
"version": "1.8.1",
|
||||||
@ -947,18 +661,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/http2-wrapper": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz",
|
|
||||||
"integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"quick-lru": "^5.1.1",
|
|
||||||
"resolve-alpn": "^1.2.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.19.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/https-proxy-agent": {
|
"node_modules/https-proxy-agent": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||||
@ -1059,17 +761,6 @@
|
|||||||
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
|
"integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/is-stream": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/isexe": {
|
"node_modules/isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||||
@ -1169,17 +860,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lowercase-keys": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
@ -1504,17 +1184,6 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/normalize-url": {
|
|
||||||
"version": "8.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz",
|
|
||||||
"integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/npmlog": {
|
"node_modules/npmlog": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
|
||||||
@ -1534,17 +1203,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/object-inspect": {
|
|
||||||
"version": "1.13.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
|
|
||||||
"integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
@ -1569,14 +1227,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz",
|
||||||
"integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ=="
|
"integrity": "sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ=="
|
||||||
},
|
},
|
||||||
"node_modules/p-cancelable": {
|
|
||||||
"version": "4.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz",
|
|
||||||
"integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/p-map": {
|
"node_modules/p-map": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
@ -1637,31 +1287,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
|
||||||
"version": "6.12.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.12.2.tgz",
|
|
||||||
"integrity": "sha512-x+NLUpx9SYrcwXtX7ob1gnkSems4i/mGZX5SlYxwIau6RrUSODO89TR/XDGGpn5RPWSYIB+aSfuSlV5+CmbTBg==",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.0.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/quick-lru": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
|
||||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/readable-stream": {
|
"node_modules/readable-stream": {
|
||||||
"version": "3.6.2",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
@ -1675,11 +1300,6 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/resolve-alpn": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
|
|
||||||
},
|
|
||||||
"node_modules/resolve-path": {
|
"node_modules/resolve-path": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz",
|
||||||
@ -1724,20 +1344,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||||
},
|
},
|
||||||
"node_modules/responselike": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
|
|
||||||
"dependencies": {
|
|
||||||
"lowercase-keys": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/retry": {
|
"node_modules/retry": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||||
@ -1805,44 +1411,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
|
||||||
},
|
},
|
||||||
"node_modules/set-function-length": {
|
|
||||||
"version": "1.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
|
||||||
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
|
|
||||||
"dependencies": {
|
|
||||||
"define-data-property": "^1.1.4",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"gopd": "^1.0.1",
|
|
||||||
"has-property-descriptors": "^1.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
||||||
},
|
},
|
||||||
"node_modules/side-channel": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
|
||||||
"dependencies": {
|
|
||||||
"call-bind": "^1.0.7",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"object-inspect": "^1.13.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/signal-exit": {
|
"node_modules/signal-exit": {
|
||||||
"version": "3.0.7",
|
"version": "3.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||||
@ -2001,10 +1574,9 @@
|
|||||||
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
"integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA=="
|
||||||
},
|
},
|
||||||
"node_modules/tar": {
|
"node_modules/tar": {
|
||||||
"version": "6.2.1",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
|
||||||
"integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
|
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chownr": "^2.0.0",
|
"chownr": "^2.0.0",
|
||||||
"fs-minipass": "^2.0.0",
|
"fs-minipass": "^2.0.0",
|
||||||
@ -2046,17 +1618,6 @@
|
|||||||
"node": ">=0.6.x"
|
"node": ">=0.6.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/type-fest": {
|
|
||||||
"version": "4.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.21.0.tgz",
|
|
||||||
"integrity": "sha512-ADn2w7hVPcK6w1I0uWnM//y1rLXZhzB9mr0a3OirzclKF1Wp6VzevUmzz/NRAWunOT6E8HrnpGY7xOfc6K57fA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/type-is": {
|
"node_modules/type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
@ -4,12 +4,10 @@
|
|||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"canvas": "^2.11.2",
|
"canvas": "^2.11.2",
|
||||||
"fast-xml-parser": "^4.3.4",
|
"fast-xml-parser": "^4.3.4",
|
||||||
"got": "^14.4.1",
|
|
||||||
"keyv": "^4.5.4",
|
"keyv": "^4.5.4",
|
||||||
"koa": "^2.14.2",
|
"koa": "^2.14.2",
|
||||||
"koa-send": "^5.0.1",
|
"koa-send": "^5.0.1",
|
||||||
"potpack": "^2.0.0",
|
"potpack": "^2.0.0"
|
||||||
"qs": "^6.12.2"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<br />
|
<br />
|
||||||
<label><input id="thumbnails" type="checkbox" checked>thumbnails</label>
|
<label><input id="thumbnails" type="checkbox" checked>thumbnails</label>
|
||||||
<label><input id="icons" type="checkbox" checked>icons</label>
|
<label><input id="icons" type="checkbox" checked>icons</label>
|
||||||
<label><input id="latestontop" type="checkbox" checked>latestontop</label>
|
<label><input id="captions" type="checkbox" checked>captions</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="output"></div>
|
<div id="output"></div>
|
||||||
@ -30,11 +30,11 @@ var lastData;
|
|||||||
|
|
||||||
search.onclick = () => {
|
search.onclick = () => {
|
||||||
output.innerHTML = "";
|
output.innerHTML = "";
|
||||||
loadData(`/search?pool=test1000&thumbnails=${thumbnails.checked}&icons=${icons.checked}&mode=${latestontop.checked&&"latestontop"}&input=${encodeURIComponent(input.value)}`);
|
loadData(`/search?pool=test1000&thumbnails=${thumbnails.checked}&icons=${icons.checked}&captions=${captions.checked}&input=${encodeURIComponent(input.value)}`);
|
||||||
};
|
};
|
||||||
trending.onclick = () => {
|
trending.onclick = () => {
|
||||||
output.innerHTML = "";
|
output.innerHTML = "";
|
||||||
loadData(`/trending?pool=test1000&thumbnails=${thumbnails.checked}&icons=${icons.checked}`);
|
loadData(`/trending?pool=test1000&thumbnails=${thumbnails.checked}&icons=${icons.checked}&captions=${captions.checked}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadData(url) {
|
async function loadData(url) {
|
||||||
|
45
util.js
45
util.js
@ -1,6 +1,3 @@
|
|||||||
import {readFileSync} from "fs";
|
|
||||||
import got from "got";
|
|
||||||
|
|
||||||
Array.prototype.filterMap = function(fn) {
|
Array.prototype.filterMap = function(fn) {
|
||||||
var newarray = [];
|
var newarray = [];
|
||||||
for (var item of this) {
|
for (var item of this) {
|
||||||
@ -10,23 +7,6 @@ Array.prototype.filterMap = function(fn) {
|
|||||||
return newarray;
|
return newarray;
|
||||||
};
|
};
|
||||||
|
|
||||||
Array.prototype.findMap = function(fn) {
|
|
||||||
for (var item of this) {
|
|
||||||
var ret = fn(item);
|
|
||||||
if (ret) return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.prototype.deepFind = function (fn) {
|
|
||||||
return (function crawlObject(object) {
|
|
||||||
for (var key in object) {
|
|
||||||
var value = object[key];
|
|
||||||
if (fn(value)) return value;
|
|
||||||
if (typeof value == "object") crawlObject(value);
|
|
||||||
}
|
|
||||||
})(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function stringToBoolean(str) {
|
export function stringToBoolean(str) {
|
||||||
if (str) {
|
if (str) {
|
||||||
if (!["0", "false", "off", "no", "null", "undefined", "nan"].includes(str.toLowerCase())) return true;
|
if (!["0", "false", "off", "no", "null", "undefined", "nan"].includes(str.toLowerCase())) return true;
|
||||||
@ -34,16 +14,15 @@ export function stringToBoolean(str) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function recursiveFind(object, fn) {
|
||||||
|
var results = [];
|
||||||
|
(function crawlObject(object) {
|
||||||
try {
|
for (var key in object) {
|
||||||
var ips = readFileSync("ips.txt", "utf8").trim().split("\n");
|
var value = object[key];
|
||||||
console.log("using ips", ips);
|
var test = fn(value);
|
||||||
} catch (e) {}
|
if (test) results.push(test);
|
||||||
|
if (typeof value == "object") crawlObject(value);
|
||||||
export function gotw(url, options = {}) {
|
}
|
||||||
if (ips) options.localAddress = ips[Math.floor(Math.random() * ips.length)];
|
})(object);
|
||||||
//options.timeout = {request: 3000}; //"RequestError: Expected values which are `number` or `undefined`. Received values of type `Function`." what the fuck?
|
return results;
|
||||||
return got(url, options);
|
}
|
||||||
}
|
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
import { XMLParser } from "fast-xml-parser";
|
import { XMLParser } from "fast-xml-parser";
|
||||||
import { gotw } from "./util.js";
|
|
||||||
|
|
||||||
var xmlParser = new XMLParser({
|
var xmlParser = new XMLParser({
|
||||||
ignoreAttributes: false
|
ignoreAttributes: false
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getVideoData(videoId) {
|
async function getVideoData(videoId) {
|
||||||
var res = await gotw(`https://www.youtube.com/watch?v=${videoId}`);
|
var html = await fetch(`https://www.youtube.com/watch?v=${videoId}`).then(res => res.text());
|
||||||
|
|
||||||
var ytInitialPlayerResponse = res.body.match(/var ytInitialPlayerResponse = ({.*});/)[1];
|
var ytInitialPlayerResponse = html.match(/var ytInitialPlayerResponse = ({.*});/)[1];
|
||||||
ytInitialPlayerResponse = JSON.parse(ytInitialPlayerResponse);
|
ytInitialPlayerResponse = JSON.parse(ytInitialPlayerResponse);
|
||||||
|
|
||||||
return ytInitialPlayerResponse;
|
return ytInitialPlayerResponse;
|
||||||
@ -19,21 +18,15 @@ async function getVideoCaptions(videoId) {
|
|||||||
if (!ytInitialPlayerResponse.captions) return [];
|
if (!ytInitialPlayerResponse.captions) return [];
|
||||||
var captionTracks = ytInitialPlayerResponse.captions.playerCaptionsTracklistRenderer.captionTracks;
|
var captionTracks = ytInitialPlayerResponse.captions.playerCaptionsTracklistRenderer.captionTracks;
|
||||||
captionTracks = await Promise.all(captionTracks.map(captionTrack => (async () => {
|
captionTracks = await Promise.all(captionTracks.map(captionTrack => (async () => {
|
||||||
try {
|
var xml = await fetch(captionTrack.baseUrl).then(res => res.text());
|
||||||
var xml = await gotw(captionTrack.baseUrl, {resolveBodyOnly: true});
|
var parsed = xmlParser.parse(xml);
|
||||||
var parsed = xmlParser.parse(xml);
|
var lines = parsed.transcript.text.map(({ "#text": text, "@_start": start, "@_dur": dur }) => ({ start: Number(start), dur: Number(dur), text }));
|
||||||
var lines = parsed.transcript.text;
|
return {
|
||||||
if (!Array.isArray(lines)) lines = [lines];
|
name: captionTrack.name.simpleText,
|
||||||
lines = lines.map(({ "#text": text, "@_start": start, "@_dur": dur }) => ({ start: Number(start), dur: Number(dur), text }));
|
id: captionTrack.vssId,
|
||||||
return {
|
lines
|
||||||
name: captionTrack.name.simpleText,
|
};
|
||||||
id: captionTrack.vssId,
|
})().catch(error => console.error(error.stack))));
|
||||||
lines
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("caption track error", error.stack, videoId, captionTrack, xml, parsed, lines);
|
|
||||||
}
|
|
||||||
})()));
|
|
||||||
return captionTracks;
|
return captionTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +37,7 @@ export async function getVideoCaptionsCached(videoId) {
|
|||||||
cache[videoId] = getVideoCaptions(videoId);
|
cache[videoId] = getVideoCaptions(videoId);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
delete cache[videoId];
|
delete cache[videoId];
|
||||||
}, 1000*60*10); // 10 minutes
|
}, 1000*60*60*6); // 6 hours
|
||||||
}
|
}
|
||||||
return await cache[videoId];
|
return await cache[videoId];
|
||||||
}
|
}
|
141
youtube.js
141
youtube.js
@ -1,49 +1,14 @@
|
|||||||
import { gotw } from "./util.js";
|
|
||||||
|
|
||||||
|
export async function searchYouTubeVideos(query) {
|
||||||
|
var url = `https://www.youtube.com/results?search_query=${encodeURIComponent(query.replaceAll(' ', '+'))}&sp=EgIQAQ%253D%253D`;
|
||||||
|
var html = await fetch(url).then(res => res.text());
|
||||||
|
|
||||||
|
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)[1];
|
||||||
|
|
||||||
export async function searchYouTubeVideos(query, sp = "EgIQAQ%253D%253D") {
|
|
||||||
console.debug("sp", sp);
|
|
||||||
var url = `https://www.youtube.com/results?search_query=${encodeURIComponent(query.replaceAll(' ', '+'))}${sp ? `$sp=${sp}` : ''}`;
|
|
||||||
var res = await gotw(url), html = res.body;
|
|
||||||
|
|
||||||
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)?.[1];
|
|
||||||
if (!ytInitialData) {
|
|
||||||
console.error("missing ytInitialData", query, res.status, html);
|
|
||||||
}
|
|
||||||
ytInitialData = JSON.parse(ytInitialData);
|
ytInitialData = JSON.parse(ytInitialData);
|
||||||
console.debug(ytInitialData);
|
console.debug(ytInitialData);
|
||||||
|
|
||||||
var sectionListRendererContents = ytInitialData
|
var videos = ytInitialData?.contents?.twoColumnSearchResultsRenderer?.primaryContents?.sectionListRenderer?.contents?.find(x => x.itemSectionRenderer?.contents?.find(x => x.videoRenderer))?.itemSectionRenderer?.contents?.filterMap(x => x.videoRenderer)?.map(parseVideoRendererData);
|
||||||
.contents
|
|
||||||
.twoColumnSearchResultsRenderer
|
|
||||||
.primaryContents
|
|
||||||
.sectionListRenderer
|
|
||||||
.contents;
|
|
||||||
|
|
||||||
var videos = sectionListRendererContents
|
|
||||||
?.find(x => x.itemSectionRenderer?.contents?.find(x => x.videoRenderer))
|
|
||||||
?.itemSectionRenderer
|
|
||||||
.contents
|
|
||||||
.filterMap(x => x.videoRenderer)
|
|
||||||
.map(parseVideoRendererData);
|
|
||||||
if (!videos) return {videos: []};
|
if (!videos) return {videos: []};
|
||||||
|
|
||||||
var latest = sectionListRendererContents
|
|
||||||
.find(x => x.itemSectionRenderer?.contents?.find(x => x.shelfRenderer))
|
|
||||||
?.itemSectionRenderer
|
|
||||||
.contents
|
|
||||||
.find(x => x.shelfRenderer?.title?.simpleText?.startsWith("Latest from"))
|
|
||||||
?.shelfRenderer
|
|
||||||
.content
|
|
||||||
.verticalListRenderer
|
|
||||||
.items
|
|
||||||
.filterMap(x => x.videoRenderer)
|
|
||||||
.map(parseVideoRendererData);
|
|
||||||
console.debug("latest", latest);
|
|
||||||
if (latest) videos = [...latest, ...videos];
|
|
||||||
|
|
||||||
console.debug(videos.length, "results");
|
console.debug(videos.length, "results");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -51,7 +16,7 @@ export async function searchYouTubeVideos(query, sp = "EgIQAQ%253D%253D") {
|
|||||||
ytcfg = JSON.parse(ytcfg);
|
ytcfg = JSON.parse(ytcfg);
|
||||||
var continuationData = {
|
var continuationData = {
|
||||||
context: ytcfg.INNERTUBE_CONTEXT,
|
context: ytcfg.INNERTUBE_CONTEXT,
|
||||||
continuation: sectionListRendererContents.findMap(x => x.continuationItemRenderer).continuationEndpoint.continuationCommand.token
|
continuation: ytInitialData.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents.find(x => x.continuationItemRenderer).continuationItemRenderer.continuationEndpoint.continuationCommand.token
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
@ -60,33 +25,19 @@ export async function searchYouTubeVideos(query, sp = "EgIQAQ%253D%253D") {
|
|||||||
return {videos, continuationData};
|
return {videos, continuationData};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function continueYouTubeVideoSearch(continuationData) {
|
export async function continueYouTubeVideoSearch(continuationData) {
|
||||||
var res = await gotw("https://www.youtube.com/youtubei/v1/search?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false", {
|
var data = await fetch("https://www.youtube.com/youtubei/v1/search?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
json: continuationData,
|
headers: {
|
||||||
responseType: "json"
|
"Content-Type": "application/json"
|
||||||
});
|
},
|
||||||
var data = res.body;
|
body: JSON.stringify(continuationData)
|
||||||
|
}).then(res => res.json());
|
||||||
console.debug(data);
|
console.debug(data);
|
||||||
|
|
||||||
var continuationItems = data
|
var continuationItems = data.onResponseReceivedCommands[0].appendContinuationItemsAction.continuationItems;
|
||||||
.onResponseReceivedCommands[0]
|
var videos = continuationItems.find(x => x.itemSectionRenderer?.contents.find(x => x.videoRenderer)).itemSectionRenderer.contents.filterMap(x => x.videoRenderer).map(parseVideoRendererData);
|
||||||
.appendContinuationItemsAction
|
var continuationToken = continuationItems.find(x => x.continuationItemRenderer)?.continuationItemRenderer.continuationEndpoint.continuationCommand.token
|
||||||
.continuationItems;
|
|
||||||
var videos = continuationItems
|
|
||||||
.find(x => x.itemSectionRenderer?.contents.find(x => x.videoRenderer))
|
|
||||||
.itemSectionRenderer
|
|
||||||
.contents
|
|
||||||
.filterMap(x => x.videoRenderer)
|
|
||||||
.map(parseVideoRendererData);
|
|
||||||
var continuationToken = continuationItems
|
|
||||||
.findMap(x => x.continuationItemRenderer)
|
|
||||||
?.continuationEndpoint
|
|
||||||
.continuationCommand
|
|
||||||
.token;
|
|
||||||
console.debug(videos.length, "results");
|
console.debug(videos.length, "results");
|
||||||
|
|
||||||
|
|
||||||
@ -101,33 +52,14 @@ export async function continueYouTubeVideoSearch(continuationData) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function getYouTubePlaylist(playlistId) {
|
export async function getYouTubePlaylist(playlistId) {
|
||||||
var res = await gotw("https://www.youtube.com/playlist?list=" + playlistId);
|
var html = await fetch("https://www.youtube.com/playlist?list=" + playlistId).then(res => res.text());
|
||||||
var html = res.body;
|
|
||||||
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)[1];
|
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)[1];
|
||||||
ytInitialData = JSON.parse(ytInitialData);
|
ytInitialData = JSON.parse(ytInitialData);
|
||||||
console.debug(ytInitialData);
|
console.debug(ytInitialData);
|
||||||
|
|
||||||
var sectionListRendererContents = ytInitialData
|
var sectionListRendererContents = ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs.find(tab => tab.tabRenderer.selected).tabRenderer.content.sectionListRenderer.contents;
|
||||||
.contents
|
var videos = sectionListRendererContents.find(x => x.itemSectionRenderer).itemSectionRenderer.contents.find(x => x.playlistVideoListRenderer).playlistVideoListRenderer.contents.filterMap(x => x.playlistVideoRenderer).map(parseVideoRendererData);
|
||||||
.twoColumnBrowseResultsRenderer
|
|
||||||
.tabs
|
|
||||||
.find(tab => tab.tabRenderer.selected)
|
|
||||||
.tabRenderer
|
|
||||||
.content
|
|
||||||
.sectionListRenderer
|
|
||||||
.contents;
|
|
||||||
var videos = sectionListRendererContents
|
|
||||||
.findMap(x => x.itemSectionRenderer?.contents)
|
|
||||||
.findMap(x => x.playlistVideoListRenderer?.contents)
|
|
||||||
.filterMap(x => x.playlistVideoRenderer)
|
|
||||||
.map(parseVideoRendererData);
|
|
||||||
if (!videos) return {videos: []};
|
if (!videos) return {videos: []};
|
||||||
console.debug(videos.length, "results");
|
console.debug(videos.length, "results");
|
||||||
|
|
||||||
@ -136,7 +68,7 @@ export async function getYouTubePlaylist(playlistId) {
|
|||||||
ytcfg = JSON.parse(ytcfg);
|
ytcfg = JSON.parse(ytcfg);
|
||||||
var continuationData = {
|
var continuationData = {
|
||||||
context: ytcfg.INNERTUBE_CONTEXT,
|
context: ytcfg.INNERTUBE_CONTEXT,
|
||||||
continuation: sectionListRendererContents.findMap(x => x.continuationItemRenderer).continuationEndpoint.continuationCommand.token
|
continuation: sectionListRendererContents.find(x => x.continuationItemRenderer).continuationItemRenderer.continuationEndpoint.continuationCommand.token
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error.stack);
|
console.error(error.stack);
|
||||||
@ -144,32 +76,18 @@ export async function getYouTubePlaylist(playlistId) {
|
|||||||
return {videos, continuationData};
|
return {videos, continuationData};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export async function continueYouTubePlaylist(continuationData) {
|
export async function continueYouTubePlaylist(continuationData) {
|
||||||
var res = await gotw("https://www.youtube.com/youtubei/v1/browse?prettyPrint=false", {
|
var data = await fetch("https://www.youtube.com/youtubei/v1/browse?prettyPrint=false", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
json: continuationData,
|
headers: {"Content-Type": "application/json"},
|
||||||
responseType: "json"
|
body: JSON.stringify(continuationData)
|
||||||
});
|
}).then(res => res.json());
|
||||||
var data = res.body;
|
|
||||||
console.debug(data);
|
console.debug(data);
|
||||||
|
|
||||||
if (!data.onResponseReceivedActions) return {videos:[]};
|
if (!data.onResponseReceivedActions) return {videos:[]};
|
||||||
var continuationItems = data
|
var continuationItems = data.onResponseReceivedActions[0].appendContinuationItemsAction.continuationItems;
|
||||||
.onResponseReceivedActions[0]
|
var videos = continuationItems.find(x => x.itemSectionRenderer).itemSectionRenderer.contents.filterMap(x => x.playlistVideoListRenderer).map(parseVideoRendererData);
|
||||||
.appendContinuationItemsAction
|
var continuationToken = continuationItems.find(x => x.continuationItemRenderer)?.continuationItemRenderer.continuationEndpoint.continuationCommand.token;
|
||||||
.continuationItems;
|
|
||||||
var videos = continuationItems
|
|
||||||
.findMap(x => x.itemSectionRenderer?.contents)
|
|
||||||
.filterMap(x => x.playlistVideoListRenderer)
|
|
||||||
.map(parseVideoRendererData);
|
|
||||||
var continuationToken = continuationItems
|
|
||||||
.findMap(x => x.continuationItemRenderer)
|
|
||||||
?.continuationEndpoint
|
|
||||||
.continuationCommand
|
|
||||||
.token;
|
|
||||||
console.debug(videos.length, "results");
|
console.debug(videos.length, "results");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -192,8 +110,7 @@ export async function continueYouTubePlaylist(continuationData) {
|
|||||||
export async function getTrending(bp) {
|
export async function getTrending(bp) {
|
||||||
var url = `https://www.youtube.com/feed/trending`;
|
var url = `https://www.youtube.com/feed/trending`;
|
||||||
if (bp) url += `?bp=${bp}`;
|
if (bp) url += `?bp=${bp}`;
|
||||||
var res = await gotw(url);
|
var html = await fetch(url).then(res => res.text());
|
||||||
var html = res.body;
|
|
||||||
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)[1];
|
var ytInitialData = html.match(/ytInitialData = ({.*});<\/script>/)[1];
|
||||||
ytInitialData = JSON.parse(ytInitialData);
|
ytInitialData = JSON.parse(ytInitialData);
|
||||||
|
|
||||||
@ -216,7 +133,7 @@ export async function getTrending(bp) {
|
|||||||
.contents
|
.contents
|
||||||
// regular trending in sections with shelfRenderer without title
|
// regular trending in sections with shelfRenderer without title
|
||||||
.filterMap(x => {
|
.filterMap(x => {
|
||||||
var shelfRenderer = x.itemSectionRenderer.contents.findMap(x => x.shelfRenderer);
|
var shelfRenderer = x.itemSectionRenderer.contents.find(x => x.shelfRenderer)?.shelfRenderer;
|
||||||
if (shelfRenderer && !shelfRenderer.title) {
|
if (shelfRenderer && !shelfRenderer.title) {
|
||||||
return shelfRenderer
|
return shelfRenderer
|
||||||
.content
|
.content
|
||||||
@ -255,7 +172,7 @@ function parseVideoRendererData(data) {
|
|||||||
description: data.detailedMetadataSnippets?.[0]?.snippetText?.runs?.concatRunsText()
|
description: data.detailedMetadataSnippets?.[0]?.snippetText?.runs?.concatRunsText()
|
||||||
|| data.descriptionSnippet?.runs?.concatRunsText(),
|
|| data.descriptionSnippet?.runs?.concatRunsText(),
|
||||||
//thumbnailUrl: data.thumbnail?.thumbnails?.find(x => (x.width == 360 && x.height == 202) || (x.width == 246 && x.height == 138))?.url || data.thumbnail?.thumbnails?.[0]?.url,
|
//thumbnailUrl: data.thumbnail?.thumbnails?.find(x => (x.width == 360 && x.height == 202) || (x.width == 246 && x.height == 138))?.url || data.thumbnail?.thumbnails?.[0]?.url,
|
||||||
thumbnail: data.thumbnail?.thumbnails?.find(x => (x.width == 360 && x.height == 202) || (x.width == 246 && x.height == 138)) || data.thumbnail?.thumbnails?.[0],
|
//thumbnail: data.thumbnail?.thumbnails?.find(x => (x.width == 360 && x.height == 202) || (x.width == 246 && x.height == 138)) || data.thumbnail?.thumbnails?.[0],
|
||||||
/*thumbnail: {
|
/*thumbnail: {
|
||||||
url: `https://i.ytimg.com/vi/${data.videoId}/mqdefault.jpg`,
|
url: `https://i.ytimg.com/vi/${data.videoId}/mqdefault.jpg`,
|
||||||
width: 320,
|
width: 320,
|
||||||
|
Loading…
Reference in New Issue
Block a user