From a09f6abc3d309593235c91da89bfd0f8100eb89d Mon Sep 17 00:00:00 2001 From: Martin Porwoll Date: Sat, 14 Feb 2026 12:29:44 +0000 Subject: [PATCH] feat: auto-download YouTube thumbnails on content create/update Co-Authored-By: Claude Opus 4.6 --- src/collections/YouTubeContent.ts | 3 +- src/hooks/youtubeContent/downloadThumbnail.ts | 43 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/hooks/youtubeContent/downloadThumbnail.ts diff --git a/src/collections/YouTubeContent.ts b/src/collections/YouTubeContent.ts index 0b918f6..39eca3f 100644 --- a/src/collections/YouTubeContent.ts +++ b/src/collections/YouTubeContent.ts @@ -8,6 +8,7 @@ import { canAccessAssignedContent, } from '../lib/youtubeAccess' import { createTasksOnStatusChange } from '../hooks/youtubeContent/createTasksOnStatusChange' +import { downloadThumbnail } from '../hooks/youtubeContent/downloadThumbnail' // TODO: ScriptSectionBlock causes admin UI rendering issues // import { ScriptSectionBlock } from '../blocks/ScriptSectionBlock' @@ -38,7 +39,7 @@ export const YouTubeContent: CollectionConfig = { delete: isYouTubeManager, }, hooks: { - afterChange: [createTasksOnStatusChange], + afterChange: [createTasksOnStatusChange, downloadThumbnail], beforeChange: [ // Auto-Slug generieren ({ data }) => { diff --git a/src/hooks/youtubeContent/downloadThumbnail.ts b/src/hooks/youtubeContent/downloadThumbnail.ts new file mode 100644 index 0000000..546a514 --- /dev/null +++ b/src/hooks/youtubeContent/downloadThumbnail.ts @@ -0,0 +1,43 @@ +import type { CollectionAfterChangeHook } from 'payload' +import { downloadAndUploadImage } from '../../lib/utils/media-download' +import { getYouTubeThumbnail } from '../../lib/utils/youtube' + +/** + * After a YouTubeContent document is created or updated, + * automatically download the YouTube thumbnail if the thumbnail field is empty + * and a YouTube videoId is present. + */ +export const downloadThumbnail: CollectionAfterChangeHook = async ({ doc, req }) => { + // Skip if thumbnail already exists (manual upload or previous download) + if (doc.thumbnail) return doc + + // Get the YouTube video ID + const videoId = doc.youtube?.videoId + if (!videoId) return doc + + const thumbnailUrl = getYouTubeThumbnail(videoId, 'hq') + const filename = `yt-thumb-${videoId}.jpg` + + const tenantId = typeof doc.tenant === 'object' ? doc.tenant?.id : doc.tenant + + const mediaId = await downloadAndUploadImage(req.payload, { + url: thumbnailUrl, + filename, + alt: doc.title + ? `Thumbnail: ${typeof doc.title === 'string' ? doc.title : doc.title?.de || doc.title?.en || videoId}` + : `YouTube Thumbnail ${videoId}`, + tenantId: tenantId || undefined, + }) + + if (mediaId) { + await req.payload.update({ + collection: 'youtube-content', + id: doc.id, + data: { thumbnail: mediaId }, + depth: 0, + }) + console.log(`[yt-thumbnail] Auto-downloaded thumbnail for video ${videoId} (media: ${mediaId})`) + } + + return doc +}