try to do more resiliant url handling
This commit is contained in:
@@ -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'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user