From 2872f32635d08a679339d5bfeda16299bdc86a80 Mon Sep 17 00:00:00 2001 From: Martin Porwoll Date: Sat, 14 Feb 2026 12:30:48 +0000 Subject: [PATCH] feat: auto-download YouTube channel images on create/update Adds channelThumbnailUrl field to store YouTube API URL. afterChange hook downloads image to Payload Media when branding.logo is empty. Co-Authored-By: Claude Opus 4.6 --- src/collections/YouTubeChannels.ts | 14 +++++++ .../youtubeChannels/downloadChannelImage.ts | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/hooks/youtubeChannels/downloadChannelImage.ts diff --git a/src/collections/YouTubeChannels.ts b/src/collections/YouTubeChannels.ts index 0769672..a784dab 100644 --- a/src/collections/YouTubeChannels.ts +++ b/src/collections/YouTubeChannels.ts @@ -2,6 +2,7 @@ import type { CollectionConfig } from 'payload' import { isYouTubeManager, hasYouTubeAccess } from '../lib/youtubeAccess' +import { downloadChannelImage } from '../hooks/youtubeChannels/downloadChannelImage' /** * YouTubeChannels Collection @@ -27,6 +28,9 @@ export const YouTubeChannels: CollectionConfig = { update: isYouTubeManager, delete: isYouTubeManager, }, + hooks: { + afterChange: [downloadChannelImage], + }, fields: [ { name: 'name', @@ -108,6 +112,16 @@ export const YouTubeChannels: CollectionConfig = { position: 'sidebar', }, }, + { + name: 'channelThumbnailUrl', + type: 'text', + label: 'Kanal-Thumbnail URL', + admin: { + readOnly: true, + description: 'Profil-Thumbnail URL von YouTube (automatisch befüllt)', + position: 'sidebar', + }, + }, // Branding { name: 'branding', diff --git a/src/hooks/youtubeChannels/downloadChannelImage.ts b/src/hooks/youtubeChannels/downloadChannelImage.ts new file mode 100644 index 0000000..f7c8d1d --- /dev/null +++ b/src/hooks/youtubeChannels/downloadChannelImage.ts @@ -0,0 +1,41 @@ +import type { CollectionAfterChangeHook } from 'payload' +import { downloadAndUploadImage } from '../../lib/utils/media-download' + +/** + * After a YouTubeChannels document is created or updated, + * automatically download the channel profile image if the branding.logo field is empty + * and a channelThumbnailUrl is available. + */ +export const downloadChannelImage: CollectionAfterChangeHook = async ({ doc, req }) => { + // Skip if logo already exists + if (doc.branding?.logo) return doc + + // Need channelThumbnailUrl (set from YouTube API or manually) + const thumbnailUrl = doc.channelThumbnailUrl + if (!thumbnailUrl) return doc + + const channelId = doc.youtubeChannelId + if (!channelId) return doc + + const filename = `yt-channel-${channelId}.jpg` + const tenantId = typeof doc.tenant === 'object' ? doc.tenant?.id : doc.tenant + + const mediaId = await downloadAndUploadImage(req.payload, { + url: thumbnailUrl, + filename, + alt: doc.name ? `Kanal: ${typeof doc.name === 'string' ? doc.name : doc.name?.de || channelId}` : `YouTube Channel ${channelId}`, + tenantId: tenantId || undefined, + }) + + if (mediaId) { + await req.payload.update({ + collection: 'youtube-channels', + id: doc.id, + data: { branding: { ...(doc.branding || {}), logo: mediaId } }, + depth: 0, + }) + console.log(`[yt-thumbnail] Auto-downloaded channel image for ${channelId} (media: ${mediaId})`) + } + + return doc +}