import type { BrowserContext } from 'playwright'; import { uploadFile, generateUniqueFileName } from '@/lib/minio'; import { downloadBinary } from './network'; import { pickFirstUrl } from './utils'; /** * 下载头像并上传到 MinIO,返回外链;失败时回退为原始链接。 */ export async function uploadAvatarFromUrl( context: BrowserContext, srcUrl?: string | null, nameHint?: string ): Promise { if (!srcUrl) return undefined; try { const { buffer, contentType, ext } = await downloadBinary(context, srcUrl); const safeExt = ext || 'jpg'; const baseName = nameHint ? `${nameHint}.${safeExt}` : `avatar.${safeExt}`; const fileName = generateUniqueFileName(baseName, 'douyin/avatars'); const uploaded = await uploadFile(buffer, fileName, { 'Content-Type': contentType }); return uploaded; } catch (e) { console.warn('[avatar] 上传失败,使用原始链接:', (e as Error)?.message || e); return srcUrl || undefined; } } /** 下载图文作品的图片和音乐并上传到 MinIO */ export async function handleImagePost( context: BrowserContext, aweme: DouyinImageAweme ): Promise<{ images: { url: string; width?: number; height?: number }[]; musicUrl?: string }> { const awemeId = aweme.aweme_id; const uploadedImages: { url: string; width?: number; height?: number }[] = []; // 下载图片(顺序保持) for (let i = 0; i < (aweme.images?.length || 0); i++) { const img = aweme.images[i]; const url = pickFirstUrl(img?.url_list); if (!url) continue; const { buffer, contentType, ext } = await downloadBinary(context, url); const safeExt = ext || 'jpg'; const fileName = generateUniqueFileName(`${awemeId}/${i}.${safeExt}`, 'douyin/images'); const uploaded = await uploadFile(buffer, fileName, { 'Content-Type': contentType }); uploadedImages.push({ url: uploaded, width: img?.width, height: img?.height }); } // 下载音乐(可选) let musicUrl: string | undefined; const audioSrc = pickFirstUrl(aweme.music?.play_url?.url_list); if (audioSrc) { const { buffer, contentType, ext } = await downloadBinary(context, audioSrc); const safeExt = ext || 'mp3'; const fileName = generateUniqueFileName(`${awemeId}.${safeExt}`, 'douyin/audios'); musicUrl = await uploadFile(buffer, fileName, { 'Content-Type': contentType }); } return { images: uploadedImages, musicUrl }; }