add innerTube as primary videoInfo endpoint

- drop videoInfo.genreUrl since it's always empty
- bump ts target to ES2021 for Promise.any
- fix mocks to return err: false
- get maxResThumbnail from static endpoint
This commit is contained in:
Michael C
2022-09-15 17:02:33 -04:00
parent 3c09033267
commit 62a9b0eddd
15 changed files with 130 additions and 109 deletions

View File

@@ -0,0 +1,59 @@
import { config } from "../config";
import { innerTubeVideoDetails } from "../types/innerTubeApi.model";
import { APIVideoData } from "../types/youtubeApi.model";
import { YouTubeAPI } from "../utils/youtubeApi";
import { getPlayerData } from "../utils/innerTubeAPI";
export interface videoDetails {
videoId: string,
duration: number,
authorId: string,
authorName: string,
title: string,
published: number,
thumbnails: {
url: string,
width: number,
height: number,
}[]
}
const convertFromInnerTube = (input: innerTubeVideoDetails): videoDetails => ({
videoId: input.videoId,
duration: Number(input.lengthSeconds),
authorId: input.channelId,
authorName: input.author,
title: input.title,
published: new Date(input.publishDate).getTime()/1000,
thumbnails: input.thumbnail.thumbnails
});
const convertFromNewLeaf = (input: APIVideoData): videoDetails => ({
videoId: input.videoId,
duration: input.lengthSeconds,
authorId: input.authorId,
authorName: input.author,
title: input.title,
published: input.published,
thumbnails: input.videoThumbnails
});
async function newLeafWrapper(videoId: string, ignoreCache: boolean) {
const result = await YouTubeAPI.listVideos(videoId, ignoreCache);
return result?.data ?? Promise.reject();
}
export function getVideoDetails(videoId: string, ignoreCache = false): Promise<videoDetails> {
if (!config.newLeafURLs) {
return getPlayerData(videoId)
.then(data => convertFromInnerTube(data));
}
return Promise.any([
newLeafWrapper(videoId, ignoreCache)
.then(videoData => convertFromNewLeaf(videoData)),
getPlayerData(videoId)
.then(data => convertFromInnerTube(data))
]).catch(() => {
return null;
});
}

View File

@@ -21,9 +21,4 @@ export async function getPlayerData(videoID: string): Promise<innerTubeVideoDeta
} else {
return Promise.reject(result.status);
}
}
export const getLength = (videoID: string): Promise<number> =>
getPlayerData(videoID)
.then(pData => Number(pData.lengthSeconds))
.catch(err => err);
}

View File

@@ -1,19 +1,13 @@
import redis from "../utils/redis";
import { tempVIPKey } from "../utils/redisKeys";
import { HashedUserID } from "../types/user.model";
import { YouTubeAPI } from "../utils/youtubeApi";
import { APIVideoInfo } from "../types/youtubeApi.model";
import { VideoID } from "../types/segments.model";
import { config } from "../config";
import { Logger } from "./logger";
function getYouTubeVideoInfo(videoID: VideoID, ignoreCache = false): Promise<APIVideoInfo> {
return config.newLeafURLs ? YouTubeAPI.listVideos(videoID, ignoreCache) : null;
}
import { getVideoDetails } from "./getVideoDetails";
export const isUserTempVIP = async (hashedUserID: HashedUserID, videoID: VideoID): Promise<boolean> => {
const apiVideoInfo = await getYouTubeVideoInfo(videoID);
const channelID = apiVideoInfo?.data?.authorId;
const apiVideoDetails = await getVideoDetails(videoID);
const channelID = apiVideoDetails?.authorId;
try {
const reply = await redis.get(tempVIPKey(hashedUserID));
return reply && reply == channelID;

View File

@@ -52,6 +52,5 @@ export class YouTubeAPI {
}
}
export function getMaxResThumbnail(apiInfo: APIVideoData): string | void {
return apiInfo?.videoThumbnails?.find((elem) => elem.quality === "maxres")?.second__originalUrl;
}
export const getMaxResThumbnail = (videoID: string): string =>
`https://i.ytimg.com/vi/${videoID}/maxresdefault.jpg`;