d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
658 lines
25 KiB
TypeScript
658 lines
25 KiB
TypeScript
import { ElevenLabsIcon, YouTubeIcon } from '@/components/icons'
|
||
import type { BlockConfig, BlockMeta } from '@/blocks/types'
|
||
import { AuthMode, IntegrationType } from '@/blocks/types'
|
||
import type { YouTubeResponse } from '@/tools/youtube/types'
|
||
|
||
export const YouTubeBlock: BlockConfig<YouTubeResponse> = {
|
||
type: 'youtube',
|
||
name: 'YouTube',
|
||
description: 'Interact with YouTube videos, channels, and playlists',
|
||
authMode: AuthMode.ApiKey,
|
||
longDescription:
|
||
'Integrate YouTube into the workflow. Can search for videos, get trending videos, get video details, get video categories, get channel information, get all videos from a channel, get channel playlists, get playlist items, and get video comments.',
|
||
docsLink: 'https://docs.sim.ai/integrations/youtube',
|
||
category: 'tools',
|
||
integrationType: IntegrationType.Communication,
|
||
bgColor: '#FF0000',
|
||
icon: YouTubeIcon,
|
||
subBlocks: [
|
||
{
|
||
id: 'operation',
|
||
title: 'Operation',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Search Videos', id: 'youtube_search' },
|
||
{ label: 'Get Trending Videos', id: 'youtube_trending' },
|
||
{ label: 'Get Video Details', id: 'youtube_video_details' },
|
||
{ label: 'Get Video Categories', id: 'youtube_video_categories' },
|
||
{ label: 'Get Channel Info', id: 'youtube_channel_info' },
|
||
{ label: 'Get Channel Videos', id: 'youtube_channel_videos' },
|
||
{ label: 'Get Channel Playlists', id: 'youtube_channel_playlists' },
|
||
{ label: 'Get Playlist Items', id: 'youtube_playlist_items' },
|
||
{ label: 'Get Video Comments', id: 'youtube_comments' },
|
||
],
|
||
value: () => 'youtube_search',
|
||
},
|
||
// Search Videos operation inputs
|
||
{
|
||
id: 'query',
|
||
title: 'Search Query',
|
||
type: 'short-input',
|
||
placeholder: 'Enter search query',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
},
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 50,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'channelId',
|
||
title: 'Filter by Channel ID',
|
||
type: 'short-input',
|
||
placeholder: 'Filter results to a specific channel',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'eventType',
|
||
title: 'Live Stream Filter',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'All Videos', id: '' },
|
||
{ label: 'Currently Live', id: 'live' },
|
||
{ label: 'Upcoming Streams', id: 'upcoming' },
|
||
{ label: 'Past Streams', id: 'completed' },
|
||
],
|
||
value: () => '',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'publishedAfter',
|
||
title: 'Published After',
|
||
type: 'short-input',
|
||
placeholder: '2024-01-01T00:00:00Z',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
wandConfig: {
|
||
enabled: true,
|
||
prompt: `Generate an ISO 8601 timestamp based on the user's description.
|
||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||
This is for filtering YouTube videos published after this date.
|
||
Examples:
|
||
- "last month" -> Calculate 30 days ago at 00:00:00Z
|
||
- "beginning of 2024" -> 2024-01-01T00:00:00Z
|
||
- "last year" -> Calculate 1 year ago at 00:00:00Z
|
||
- "past 7 days" -> Calculate 7 days ago at 00:00:00Z
|
||
|
||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||
placeholder: 'Describe the start date (e.g., "last month", "beginning of 2024")...',
|
||
generationType: 'timestamp',
|
||
},
|
||
},
|
||
{
|
||
id: 'publishedBefore',
|
||
title: 'Published Before',
|
||
type: 'short-input',
|
||
placeholder: '2024-12-31T23:59:59Z',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
wandConfig: {
|
||
enabled: true,
|
||
prompt: `Generate an ISO 8601 timestamp based on the user's description.
|
||
The timestamp should be in the format: YYYY-MM-DDTHH:mm:ssZ (UTC timezone).
|
||
This is for filtering YouTube videos published before this date.
|
||
Examples:
|
||
- "today" -> Today's date at 23:59:59Z
|
||
- "end of 2024" -> 2024-12-31T23:59:59Z
|
||
- "yesterday" -> Yesterday's date at 23:59:59Z
|
||
- "end of last month" -> Last day of previous month at 23:59:59Z
|
||
|
||
Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||
placeholder: 'Describe the end date (e.g., "today", "end of last year")...',
|
||
generationType: 'timestamp',
|
||
},
|
||
},
|
||
{
|
||
id: 'videoDuration',
|
||
title: 'Video Duration',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Any', id: 'any' },
|
||
{ label: 'Short (<4 min)', id: 'short' },
|
||
{ label: 'Medium (4-20 min)', id: 'medium' },
|
||
{ label: 'Long (>20 min)', id: 'long' },
|
||
],
|
||
value: () => 'any',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'order',
|
||
title: 'Sort Order',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Relevance', id: 'relevance' },
|
||
{ label: 'Date (Newest First)', id: 'date' },
|
||
{ label: 'View Count', id: 'viewCount' },
|
||
{ label: 'Rating', id: 'rating' },
|
||
{ label: 'Title', id: 'title' },
|
||
],
|
||
value: () => 'relevance',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'videoCategoryId',
|
||
title: 'Category ID',
|
||
type: 'short-input',
|
||
placeholder: 'Use Get Video Categories to find IDs',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'videoDefinition',
|
||
title: 'Video Quality',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Any', id: 'any' },
|
||
{ label: 'HD', id: 'high' },
|
||
{ label: 'Standard', id: 'standard' },
|
||
],
|
||
value: () => 'any',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'videoCaption',
|
||
title: 'Captions',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Any', id: 'any' },
|
||
{ label: 'Has Captions', id: 'closedCaption' },
|
||
{ label: 'No Captions', id: 'none' },
|
||
],
|
||
value: () => 'any',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'regionCode',
|
||
title: 'Region Code',
|
||
type: 'short-input',
|
||
placeholder: 'US, GB, JP',
|
||
condition: {
|
||
field: 'operation',
|
||
value: ['youtube_search', 'youtube_trending', 'youtube_video_categories'],
|
||
},
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'relevanceLanguage',
|
||
title: 'Language Code',
|
||
type: 'short-input',
|
||
placeholder: 'en, es, fr',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'safeSearch',
|
||
title: 'Safe Search',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Moderate', id: 'moderate' },
|
||
{ label: 'None', id: 'none' },
|
||
{ label: 'Strict', id: 'strict' },
|
||
],
|
||
value: () => 'moderate',
|
||
condition: { field: 'operation', value: 'youtube_search' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Trending Videos operation inputs
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 50,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_trending' },
|
||
},
|
||
{
|
||
id: 'videoCategoryId',
|
||
title: 'Category ID',
|
||
type: 'short-input',
|
||
placeholder: 'Use Get Video Categories to find IDs',
|
||
condition: { field: 'operation', value: 'youtube_trending' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_trending' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Video Details operation inputs
|
||
{
|
||
id: 'videoId',
|
||
title: 'Video ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube video ID',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_video_details' },
|
||
},
|
||
// Get Video Categories operation inputs
|
||
{
|
||
id: 'hl',
|
||
title: 'Language',
|
||
type: 'short-input',
|
||
placeholder: 'en, es, fr (for category names)',
|
||
condition: { field: 'operation', value: 'youtube_video_categories' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Channel Info operation inputs
|
||
{
|
||
id: 'channelId',
|
||
title: 'Channel ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter channel ID (or leave blank to use username)',
|
||
condition: { field: 'operation', value: 'youtube_channel_info' },
|
||
},
|
||
{
|
||
id: 'username',
|
||
title: 'Channel Username',
|
||
type: 'short-input',
|
||
placeholder: 'Enter channel username (if not using channel ID)',
|
||
condition: { field: 'operation', value: 'youtube_channel_info' },
|
||
},
|
||
// Get Channel Videos operation inputs
|
||
{
|
||
id: 'channelId',
|
||
title: 'Channel ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube channel ID',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_channel_videos' },
|
||
},
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 50,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_channel_videos' },
|
||
},
|
||
{
|
||
id: 'order',
|
||
title: 'Sort Order',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Date (Newest First)', id: 'date' },
|
||
{ label: 'Relevance', id: 'relevance' },
|
||
{ label: 'View Count', id: 'viewCount' },
|
||
{ label: 'Rating', id: 'rating' },
|
||
{ label: 'Title', id: 'title' },
|
||
],
|
||
value: () => 'date',
|
||
condition: { field: 'operation', value: 'youtube_channel_videos' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_channel_videos' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Channel Playlists operation inputs
|
||
{
|
||
id: 'channelId',
|
||
title: 'Channel ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube channel ID',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_channel_playlists' },
|
||
},
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 50,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_channel_playlists' },
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_channel_playlists' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Playlist Items operation inputs
|
||
{
|
||
id: 'playlistId',
|
||
title: 'Playlist ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube playlist ID',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_playlist_items' },
|
||
},
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 50,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_playlist_items' },
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_playlist_items' },
|
||
mode: 'advanced',
|
||
},
|
||
// Get Video Comments operation inputs
|
||
{
|
||
id: 'videoId',
|
||
title: 'Video ID',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube video ID',
|
||
required: true,
|
||
condition: { field: 'operation', value: 'youtube_comments' },
|
||
},
|
||
{
|
||
id: 'maxResults',
|
||
title: 'Max Results',
|
||
type: 'slider',
|
||
min: 1,
|
||
max: 100,
|
||
step: 1,
|
||
integer: true,
|
||
condition: { field: 'operation', value: 'youtube_comments' },
|
||
},
|
||
{
|
||
id: 'order',
|
||
title: 'Sort Order',
|
||
type: 'dropdown',
|
||
options: [
|
||
{ label: 'Most Relevant', id: 'relevance' },
|
||
{ label: 'Most Recent', id: 'time' },
|
||
],
|
||
value: () => 'relevance',
|
||
condition: { field: 'operation', value: 'youtube_comments' },
|
||
mode: 'advanced',
|
||
},
|
||
{
|
||
id: 'pageToken',
|
||
title: 'Page Token',
|
||
type: 'short-input',
|
||
placeholder: 'Token for pagination (from nextPageToken)',
|
||
condition: { field: 'operation', value: 'youtube_comments' },
|
||
mode: 'advanced',
|
||
},
|
||
// API Key (common to all operations)
|
||
{
|
||
id: 'apiKey',
|
||
title: 'YouTube API Key',
|
||
type: 'short-input',
|
||
placeholder: 'Enter YouTube API Key',
|
||
password: true,
|
||
required: true,
|
||
},
|
||
],
|
||
tools: {
|
||
access: [
|
||
'youtube_channel_info',
|
||
'youtube_channel_playlists',
|
||
'youtube_channel_videos',
|
||
'youtube_comments',
|
||
'youtube_playlist_items',
|
||
'youtube_search',
|
||
'youtube_trending',
|
||
'youtube_video_categories',
|
||
'youtube_video_details',
|
||
],
|
||
config: {
|
||
tool: (params) => {
|
||
switch (params.operation) {
|
||
case 'youtube_search':
|
||
return 'youtube_search'
|
||
case 'youtube_trending':
|
||
return 'youtube_trending'
|
||
case 'youtube_video_details':
|
||
return 'youtube_video_details'
|
||
case 'youtube_video_categories':
|
||
return 'youtube_video_categories'
|
||
case 'youtube_channel_info':
|
||
return 'youtube_channel_info'
|
||
case 'youtube_channel_videos':
|
||
return 'youtube_channel_videos'
|
||
case 'youtube_channel_playlists':
|
||
return 'youtube_channel_playlists'
|
||
case 'youtube_playlist_items':
|
||
return 'youtube_playlist_items'
|
||
case 'youtube_comments':
|
||
return 'youtube_comments'
|
||
default:
|
||
return 'youtube_search'
|
||
}
|
||
},
|
||
params: (params) => {
|
||
const result: Record<string, unknown> = {}
|
||
if (params.maxResults) result.maxResults = Number(params.maxResults)
|
||
return result
|
||
},
|
||
},
|
||
},
|
||
inputs: {
|
||
operation: { type: 'string', description: 'Operation to perform' },
|
||
apiKey: { type: 'string', description: 'YouTube API key' },
|
||
// Search Videos
|
||
query: { type: 'string', description: 'Search query' },
|
||
maxResults: { type: 'number', description: 'Maximum number of results' },
|
||
pageToken: { type: 'string', description: 'Page token for pagination' },
|
||
// Search Filters
|
||
publishedAfter: { type: 'string', description: 'Published after date (RFC 3339)' },
|
||
publishedBefore: { type: 'string', description: 'Published before date (RFC 3339)' },
|
||
videoDuration: { type: 'string', description: 'Video duration filter' },
|
||
videoCategoryId: { type: 'string', description: 'YouTube category ID' },
|
||
videoDefinition: { type: 'string', description: 'Video quality filter' },
|
||
videoCaption: { type: 'string', description: 'Caption availability filter' },
|
||
eventType: { type: 'string', description: 'Live stream filter (live/upcoming/completed)' },
|
||
regionCode: { type: 'string', description: 'Region code (ISO 3166-1)' },
|
||
relevanceLanguage: { type: 'string', description: 'Language code (ISO 639-1)' },
|
||
safeSearch: { type: 'string', description: 'Safe search level' },
|
||
hl: { type: 'string', description: 'Language for category names' },
|
||
// Video Details & Comments
|
||
videoId: { type: 'string', description: 'YouTube video ID' },
|
||
// Channel Info
|
||
channelId: { type: 'string', description: 'YouTube channel ID' },
|
||
username: { type: 'string', description: 'YouTube channel username' },
|
||
// Playlist Items
|
||
playlistId: { type: 'string', description: 'YouTube playlist ID' },
|
||
// Sort Order (used by multiple operations)
|
||
order: { type: 'string', description: 'Sort order' },
|
||
},
|
||
outputs: {
|
||
// Search Videos, Trending, Playlist Items, Captions, Categories
|
||
items: { type: 'json', description: 'List of items returned' },
|
||
totalResults: { type: 'number', description: 'Total number of results' },
|
||
nextPageToken: { type: 'string', description: 'Token for next page' },
|
||
// Video Details
|
||
videoId: { type: 'string', description: 'Video ID' },
|
||
title: { type: 'string', description: 'Video or channel title' },
|
||
description: { type: 'string', description: 'Video or channel description' },
|
||
channelId: { type: 'string', description: 'Channel ID' },
|
||
channelTitle: { type: 'string', description: 'Channel name' },
|
||
publishedAt: { type: 'string', description: 'Published date' },
|
||
duration: { type: 'string', description: 'Video duration' },
|
||
viewCount: { type: 'number', description: 'View count' },
|
||
likeCount: { type: 'number', description: 'Like count' },
|
||
commentCount: { type: 'number', description: 'Comment count' },
|
||
favoriteCount: { type: 'number', description: 'Favorite count' },
|
||
thumbnail: { type: 'string', description: 'Thumbnail URL' },
|
||
tags: { type: 'json', description: 'Video tags' },
|
||
categoryId: { type: 'string', description: 'Video category ID' },
|
||
definition: { type: 'string', description: 'Video definition (hd/sd)' },
|
||
caption: { type: 'string', description: 'Has captions (true/false)' },
|
||
licensedContent: { type: 'boolean', description: 'Is licensed content' },
|
||
privacyStatus: { type: 'string', description: 'Privacy status' },
|
||
liveBroadcastContent: { type: 'string', description: 'Live broadcast status' },
|
||
defaultLanguage: { type: 'string', description: 'Default language' },
|
||
defaultAudioLanguage: { type: 'string', description: 'Default audio language' },
|
||
// Live Streaming Details
|
||
isLiveContent: { type: 'boolean', description: 'Whether video is/was a live stream' },
|
||
scheduledStartTime: { type: 'string', description: 'Scheduled start time for live streams' },
|
||
actualStartTime: { type: 'string', description: 'Actual start time of live stream' },
|
||
actualEndTime: { type: 'string', description: 'End time of live stream' },
|
||
concurrentViewers: { type: 'number', description: 'Current viewers (live only)' },
|
||
activeLiveChatId: { type: 'string', description: 'Live chat ID' },
|
||
// Channel Info
|
||
subscriberCount: { type: 'number', description: 'Subscriber count' },
|
||
videoCount: { type: 'number', description: 'Total video count' },
|
||
customUrl: { type: 'string', description: 'Channel custom URL' },
|
||
country: { type: 'string', description: 'Channel country' },
|
||
uploadsPlaylistId: { type: 'string', description: 'Uploads playlist ID' },
|
||
bannerImageUrl: { type: 'string', description: 'Channel banner URL' },
|
||
hiddenSubscriberCount: { type: 'boolean', description: 'Is subscriber count hidden' },
|
||
// Video Categories
|
||
assignable: { type: 'boolean', description: 'Whether category can be assigned' },
|
||
},
|
||
}
|
||
|
||
export const YouTubeBlockMeta = {
|
||
tags: ['marketing', 'content-management'],
|
||
url: 'https://www.youtube.com',
|
||
templates: [
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'Content repurposer',
|
||
prompt:
|
||
'Build a workflow that takes a YouTube video URL, pulls the video details and description, researches the topic on the web for additional context, and generates a Twitter thread, LinkedIn post, and blog summary optimized for each platform.',
|
||
modules: ['agent', 'files', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'content', 'automation'],
|
||
},
|
||
{
|
||
icon: ElevenLabsIcon,
|
||
title: 'YouTube video audio brief',
|
||
prompt:
|
||
'Build a workflow that takes a YouTube URL, pulls the video details and top comments, summarizes them with an agent, narrates the summary with ElevenLabs, and saves the audio file for distribution.',
|
||
modules: ['agent', 'files', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['content', 'automation'],
|
||
alsoIntegrations: ['elevenlabs'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube channel performance digest',
|
||
prompt:
|
||
'Create a scheduled weekly workflow that pulls a YouTube channel’s public stats and recent videos, ranks the top performers by views, writes a digest file, and emails it to the content team.',
|
||
modules: ['scheduled', 'agent', 'files', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'reporting'],
|
||
alsoIntegrations: ['gmail'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube comment triage',
|
||
prompt:
|
||
'Build a scheduled workflow that pulls recent YouTube comments on a video, classifies each as helpful, question, or spam, drafts suggested answers to questions using a knowledge base, and routes them to the community team in Slack for review.',
|
||
modules: ['scheduled', 'knowledge-base', 'agent', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'community'],
|
||
alsoIntegrations: ['slack'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube upload-to-blog',
|
||
prompt:
|
||
'Create a scheduled workflow that polls a YouTube channel for new uploads, pulls each video’s details and description, generates a long-form blog post with proper SEO structure, and stages it as a WordPress draft.',
|
||
modules: ['scheduled', 'agent', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'content'],
|
||
alsoIntegrations: ['wordpress'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube competitor watcher',
|
||
prompt:
|
||
'Build a scheduled workflow that monitors competitor YouTube channels, flags videos that exceed average performance, and writes outline of their format to a content-research table.',
|
||
modules: ['scheduled', 'tables', 'agent', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'research'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube video curation finder',
|
||
prompt:
|
||
'Create a workflow that reads a tables-based topic list, finds matching YouTube videos via search, scores each for relevance, writes the candidates back to the table, and pings the editorial team for the final cut.',
|
||
modules: ['tables', 'agent', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'content'],
|
||
},
|
||
{
|
||
icon: YouTubeIcon,
|
||
title: 'YouTube video recap to Notion',
|
||
prompt:
|
||
'Build a workflow that takes a YouTube video URL, pulls the video details, description, and top comments, summarizes the highlights and audience reaction, and saves a recap to a Notion page for the marketing team.',
|
||
modules: ['agent', 'workflows'],
|
||
category: 'marketing',
|
||
tags: ['marketing', 'content'],
|
||
alsoIntegrations: ['notion'],
|
||
},
|
||
],
|
||
skills: [
|
||
{
|
||
name: 'find-videos-on-topic',
|
||
description:
|
||
'Search YouTube for videos on a topic with filters for duration, recency, and quality.',
|
||
content:
|
||
'# Find YouTube Videos on a Topic\n\nSurface the most relevant videos for a subject.\n\n## Steps\n1. Build a search query and choose filters: order (relevance, date, view count), duration, and definition.\n2. Call the search operation with a result limit.\n3. For promising results, get video details to read title, channel, view count, and publish date.\n4. Rank the results by relevance and signal.\n\n## Output\nReturn a ranked list of videos with title, channel, URL, view count, and publish date. Note the query and filters applied.',
|
||
},
|
||
{
|
||
name: 'analyze-channel',
|
||
description:
|
||
'Pull a YouTube channel profile and recent uploads to summarize its content and cadence.',
|
||
content:
|
||
'# Analyze a YouTube Channel\n\nProfile a channel and its recent output.\n\n## Steps\n1. Get channel info to retrieve subscriber count, total views, and description.\n2. Get channel videos to list recent uploads.\n3. Summarize the content themes, upload cadence, and the best-performing recent videos.\n\n## Output\nReturn a channel summary with key stats, dominant content themes, posting frequency, and the top recent videos by views. Cite the channel and video IDs used.',
|
||
},
|
||
{
|
||
name: 'summarize-video-comments',
|
||
description:
|
||
'Fetch comments on a YouTube video and summarize sentiment, questions, and recurring feedback.',
|
||
content:
|
||
'# Summarize YouTube Video Comments\n\nUnderstand audience reaction to a video.\n\n## Steps\n1. Identify the video ID, searching or using video details if only a title is known.\n2. Call the comments operation to fetch top or recent comments.\n3. Group comments into sentiment, recurring questions, and feature or content requests.\n\n## Output\nReturn a summary with sentiment breakdown, the most common questions, and notable feedback themes. Quote a few representative comments and cite the video ID.',
|
||
},
|
||
],
|
||
} as const satisfies BlockMeta
|