// Server-side provider registry for search fan-out // Each provider module should export an object with a `search(q, opts)` function returning Promise /** * @typedef {Object} Suggestion * @property {string} title * @property {string} id * @property {number=} duration * @property {boolean=} isShort * @property {string=} url * @property {string=} thumbnail * @property {string=} uploaderName * @property {string=} type */ /** @typedef {'yt'|'dm'|'tw'|'pt'|'od'|'ru'} ProviderId */ import channelRegistry from './channel-registry.mjs'; /** * @typedef {Object} ProviderAdapter * @property {ProviderId} id * @property {string} label * @property {(q: string, opts: { limit: number, page?: number, sort?: string }) => Promise} search * @property {(q: string, opts?: { limit?: number }) => Promise} [suggest] * @property {(externalId: string, ctx?: any) => Promise} */ export const providerRegistry = { /** @type {any} */ yt: (await import('./youtube.mjs')).default, /** @type {any} */ dm: (await import('./dailymotion.mjs')).default, /** @type {any} */ tw: (await import('./twitch.mjs')).default, /** @type {any} */ pt: (await import('./peertube.mjs')).default, /** @type {any} */ od: (await import('./odysee.mjs')).default, /** @type {any} */ ru: (await import('./rumble.mjs')).default, }; for (const [pid, adapter] of Object.entries(providerRegistry)) { const channelAdapter = channelRegistry[/** @type {ProviderId} */(pid)]; if (channelAdapter && typeof channelAdapter.fetchChannelById === 'function' && !adapter.fetchChannelById) { adapter.fetchChannelById = channelAdapter.fetchChannelById; } } /** * Validate and normalize a comma separated providers list * @param {string} input * @returns {ProviderId[]} */ export function validateProviders(input) { const raw = String(input || '').split(',').map(s => s.trim()).filter(Boolean); const allowed = /** @type {ProviderId[]} */(['yt','dm','tw','pt','od','ru']); const filtered = raw.filter(p => allowed.includes(/** @type {any} */(p))); if (filtered.length === 0) return allowed; return /** @type {ProviderId[]} */(filtered); }