diff --git a/src/InvidiousAPI.ts b/src/InvidiousAPI.ts index 70ea031..cbb5b46 100644 --- a/src/InvidiousAPI.ts +++ b/src/InvidiousAPI.ts @@ -24,6 +24,11 @@ export interface SearchResult { thumbnailUrl: string; } +export interface ThumbnailResponse { + data: NodeJS.ReadableStream; + contentType: string; +} + const USE_INVIDIOUS = process.env.USE_INVIDIOUS || true; const INVIDIOUS_BASE_URL = process.env.INVIDIOUS_BASE_URL || 'http://invidious.nor'; const INVIDIOUS_API_ENDPOINT = `${INVIDIOUS_BASE_URL}/api/v1`; @@ -76,3 +81,22 @@ export const searchInvidious = async (query: string): Promise => throw error; } } + +export const fetchThumbnail = async (thumbnailUrl: string): Promise => { + let path = thumbnailUrl; + if (thumbnailUrl.startsWith('http://') || thumbnailUrl.startsWith('https://')) { + const url = new URL(thumbnailUrl); + path = url.pathname + url.search; + } + path = path.replace(/^\/+/, ''); // Strip leading slash + + const response = await fetch(getInvidiousThumbnailURL(path)); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return { + data: response.body, + contentType: response.headers.get('content-type') || 'image/jpeg' + }; +}; diff --git a/src/server.ts b/src/server.ts index 0163faa..1189a98 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,7 +1,7 @@ import express from "express"; import expressWs from "express-ws"; import { MediaPlayer } from "./MediaPlayer"; -import { searchInvidious, getInvidiousThumbnailURL } from "./InvidiousAPI"; +import { searchInvidious, getInvidiousThumbnailURL, fetchThumbnail } from "./InvidiousAPI"; import fetch from "node-fetch"; const app = express(); @@ -118,17 +118,9 @@ apiRouter.get("/thumbnail", withErrorHandling(async (req, res) => { } try { - const thumbnailUrlWithoutLeadingSlash = thumbnailUrl.startsWith('/') ? thumbnailUrl.slice(1) : thumbnailUrl; - const response = await fetch(getInvidiousThumbnailURL(thumbnailUrlWithoutLeadingSlash)); - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - // Forward the content type header - res.set('Content-Type', response.headers.get('content-type') || 'image/jpeg'); - - // Pipe the thumbnail data directly to the response - response.body.pipe(res); + const { data, contentType } = await fetchThumbnail(thumbnailUrl); + res.set('Content-Type', contentType); + data.pipe(res); } catch (error) { console.error('Failed to proxy thumbnail:', error); res.status(500)