try to do more resiliant url handling

This commit is contained in:
2025-02-22 02:18:17 -08:00
parent fbfd20c965
commit 5c3f2dbdd2
2 changed files with 28 additions and 12 deletions

View File

@@ -24,6 +24,11 @@ export interface SearchResult {
thumbnailUrl: string; thumbnailUrl: string;
} }
export interface ThumbnailResponse {
data: NodeJS.ReadableStream;
contentType: string;
}
const USE_INVIDIOUS = process.env.USE_INVIDIOUS || true; const USE_INVIDIOUS = process.env.USE_INVIDIOUS || true;
const INVIDIOUS_BASE_URL = process.env.INVIDIOUS_BASE_URL || 'http://invidious.nor'; const INVIDIOUS_BASE_URL = process.env.INVIDIOUS_BASE_URL || 'http://invidious.nor';
const INVIDIOUS_API_ENDPOINT = `${INVIDIOUS_BASE_URL}/api/v1`; const INVIDIOUS_API_ENDPOINT = `${INVIDIOUS_BASE_URL}/api/v1`;
@@ -76,3 +81,22 @@ export const searchInvidious = async (query: string): Promise<SearchResult[]> =>
throw error; throw error;
} }
} }
export const fetchThumbnail = async (thumbnailUrl: string): Promise<ThumbnailResponse> => {
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'
};
};

View File

@@ -1,7 +1,7 @@
import express from "express"; import express from "express";
import expressWs from "express-ws"; import expressWs from "express-ws";
import { MediaPlayer } from "./MediaPlayer"; import { MediaPlayer } from "./MediaPlayer";
import { searchInvidious, getInvidiousThumbnailURL } from "./InvidiousAPI"; import { searchInvidious, getInvidiousThumbnailURL, fetchThumbnail } from "./InvidiousAPI";
import fetch from "node-fetch"; import fetch from "node-fetch";
const app = express(); const app = express();
@@ -118,17 +118,9 @@ apiRouter.get("/thumbnail", withErrorHandling(async (req, res) => {
} }
try { try {
const thumbnailUrlWithoutLeadingSlash = thumbnailUrl.startsWith('/') ? thumbnailUrl.slice(1) : thumbnailUrl; const { data, contentType } = await fetchThumbnail(thumbnailUrl);
const response = await fetch(getInvidiousThumbnailURL(thumbnailUrlWithoutLeadingSlash)); res.set('Content-Type', contentType);
if (!response.ok) { data.pipe(res);
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);
} catch (error) { } catch (error) {
console.error('Failed to proxy thumbnail:', error); console.error('Failed to proxy thumbnail:', error);
res.status(500) res.status(500)