NewTube/server/providers/odysee.mjs

63 lines
2.1 KiB
JavaScript

/**
* Minimal Odysee provider handler
*/
const handler = {
id: 'od',
label: 'Odysee',
/**
* @param {string} q
* @param {{ limit: number, page?: number }} opts
* @returns {Promise<Array<any>>}
*/
async search(q, opts) {
const { limit = 10, page = 1 } = opts || {};
try {
const perPage = Math.min(Math.max(1, Number(limit || 10)), 50);
const pageNum = Math.max(1, Number(page || 1));
const params = new URLSearchParams({
s: q,
size: perPage.toString(),
from: ((pageNum - 1) * perPage).toString(),
include: 'channel,thumbnail_url,title,description,duration,release_time,claimId,name',
mediaType: 'video'
});
const response = await fetch(`https://lighthouse.odysee.tv/search?${params.toString()}`);
if (!response.ok) {
throw new Error(`Odysee API error: ${response.status}`);
}
const data = await response.json();
return (Array.isArray(data) ? data : []).map(item => {
const rawThumb = item.thumbnail_url || '';
const thumbnail = rawThumb
? rawThumb.startsWith('http')
? rawThumb
: `https://thumbnails.odycdn.com/optimize/s:390:0/quality:85/plain/${rawThumb.replace(/^\//, '')}`
: undefined;
const name = item.name || '';
const claimId = item.claimId || item.claim_id || '';
const urlSegment = claimId ? `${encodeURIComponent(name)}:${claimId}` : encodeURIComponent(name);
return {
title: item.title || name,
id: claimId || name,
url: claimId ? `https://odysee.com/${urlSegment}` : `https://odysee.com/${encodeURIComponent(name)}`,
thumbnail,
uploaderName: item.channel || undefined,
type: 'video',
duration: typeof item.duration === 'number' && item.duration > 0
? Math.round(item.duration)
: (typeof item.video?.duration === 'number' && item.video.duration > 0 ? Math.round(item.video.duration) : undefined)
};
});
} catch (error) {
console.error('Odysee search error:', error);
return [];
}
}
};
export default handler;