diff --git a/src/api/playback.ts b/src/api/playback.ts index f1c30f7..f817ebc 100644 --- a/src/api/playback.ts +++ b/src/api/playback.ts @@ -10,14 +10,17 @@ playback.get( zValidator("param", VideoFindSchema), async (c) => { const { id } = c.req.valid("param"); + const data = await innertube.getStreamingData(id, { type: "video+audio", quality: "best", format: "mp4", client: "TV", }); - if (!data.url) return c.status(400); - return c.redirect(data.url, 307); + + return data.url + ? c.redirect(data.url, 307) + : c.status(400); } ) diff --git a/src/api/video.ts b/src/api/video.ts index bd16a38..e68574c 100644 --- a/src/api/video.ts +++ b/src/api/video.ts @@ -3,7 +3,7 @@ import innertube from "../lib/innertube.js"; import { zValidator } from "@hono/zod-validator"; import { VideoSearchSchema } from "../models/VideoSearchSchema.js"; import search from "../templates/search.js"; -import { parseVideos } from "../lib/utils/video.js"; +import { parseVideo } from "../lib/utils/video.js"; import { YTNodes } from "youtubei.js"; const video = new Hono(); @@ -30,27 +30,25 @@ video.get( let currentPage = 1; - while (currentPage <= page) { + while (currentPage <= page && searchQuery.has_continuation) { const videos = searchQuery.results.filter( (node): node is YTNodes.Video => node.type === "Video" ); allVideos.push(...videos); - - if (!searchQuery.has_continuation) break; if (currentPage === page) break; searchQuery = await searchQuery.getContinuation(); currentPage++; } - // * build next page URL + // * build next page url const nextUrl = new URL(c.req.url); nextUrl.searchParams.set("start-index", String(page + 1)); return c.html( search( - parseVideos(allVideos), + allVideos.map(video => parseVideo(video)), searchQuery.has_continuation ? nextUrl.toString() : "" ) ); diff --git a/src/index.ts b/src/index.ts index ede89b7..7fd841d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,9 @@ -import "dotenv/config" import { Hono } from "hono" import { logger } from "hono/logger" import { serve } from "@hono/node-server" import { serveStatic } from "@hono/node-server/serve-static" import { config } from "./lib/config.js" +import "dotenv/config" import video from "./api/video.js" import playback from "./api/playback.js" diff --git a/src/lib/config.ts b/src/lib/config.ts index 8929595..585663f 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -2,10 +2,9 @@ import { z } from "zod"; import fs from "fs"; import path from "path"; -const cookiesPath = path.resolve(process.cwd(), "cookies.txt"); - let cookies: string | null = null; +const cookiesPath = path.resolve(process.cwd(), "cookies.txt"); if (fs.existsSync(cookiesPath)) { cookies = fs.readFileSync(cookiesPath, "utf8").trim(); } diff --git a/src/lib/innertube.ts b/src/lib/innertube.ts index 881820e..42e3533 100644 --- a/src/lib/innertube.ts +++ b/src/lib/innertube.ts @@ -20,4 +20,5 @@ const innertube = await Innertube.create({ client_type: ClientType.WEB, ...(config.COOKIES ? { cookie: config.COOKIES } : {}) }); + export default innertube \ No newline at end of file diff --git a/src/lib/utils/feed.ts b/src/lib/utils/feed.ts index 93fbb98..79a51c3 100644 --- a/src/lib/utils/feed.ts +++ b/src/lib/utils/feed.ts @@ -17,8 +17,8 @@ export function parseFeedVideo( // * extract author info const authorPart = metadataRows[0]?.metadata_parts?.[0]?.text; - const authorName = authorPart?.text ?? ""; const authorId = authorPart?.endpoint?.payload?.browseId ?? ""; + const authorName = authorPart?.text ?? ""; // * extract view count and published date const viewText = metadataRows[1]?.metadata_parts?.[0]?.text?.text ?? "0"; diff --git a/src/lib/utils/video.ts b/src/lib/utils/video.ts index 2b71e94..d950762 100644 --- a/src/lib/utils/video.ts +++ b/src/lib/utils/video.ts @@ -13,10 +13,6 @@ export interface Video { created: string; } -export function parseVideos(videos: YTNodes.Video[]): Video[] { - return videos.map(video => parseVideo(video)); -} - export function parseVideo(video: YTNodes.Video): Video { const authorId = video.author?.id && video.author.id !== "N/A" ? video.author.id