nexstream-deploy
deploy: nexstream backend (experiment)
2276d59
Raw
History Blame Contribute Delete
2.2 kB
import { VideoInfo, Format } from '../../../types/index.js';
import { normalizeTitle, normalizeArtist } from '../../social.service.js';
import { ThreadsParsed } from './types.js';
export function normalizeVideoInfo(
url: string,
parsedData: ThreadsParsed | null
): VideoInfo | null {
if (!parsedData) return null;
const formats: Format[] = parsedData.formats.map((formatItem, index) => {
const isPhoto = formatItem.format_id?.startsWith('photo') ?? false;
const vcodec = formatItem.vcodec ?? (isPhoto ? undefined : 'h264');
const acodec = formatItem.acodec ?? (isPhoto ? undefined : 'aac');
const { width, height } = formatItem;
// label when dimensions are unavailable
const tier =
formatItem.format_id === 'hd'
? 'HD'
: formatItem.format_id === 'sd'
? 'SD'
: isPhoto
? 'Photo'
: undefined;
const quality = height ? `${height}p` : tier;
return {
formatId: formatItem.format_id || `th_${index}`,
url: formatItem.url,
extension: formatItem.ext ?? 'mp4',
resolution: width && height ? `${width}x${height}` : (tier ?? 'Source'),
quality,
width,
height,
vcodec,
acodec,
isAudio: Boolean(acodec && acodec !== 'none'),
isVideo: Boolean(vcodec && vcodec !== 'none'),
isMuxed: Boolean(
acodec && acodec !== 'none' && vcodec && vcodec !== 'none'
),
};
});
if (formats.length === 0) return null;
const info: VideoInfo = {
type: 'video',
id: parsedData.id || url,
title: parsedData.title || 'Threads Post',
uploader: parsedData.uploader || 'Threads User',
thumbnail: parsedData.thumbnail || undefined,
webpageUrl: url,
formats,
extractorKey: 'threads',
isJsInfo: true,
fromBrain: false,
isPartial: false,
isIsrcMatch: false,
isFullData: false,
};
// make caption authoritative over og:title
if (parsedData.title) {
info.metascraper = { title: parsedData.title };
}
info.title = normalizeTitle(info as unknown as Record<string, unknown>);
info.uploader = normalizeArtist(info as unknown as Record<string, unknown>);
return info;
}