@memberjunction/actions-bizapps-social
Version:
Social Media Actions for MemberJunction - Twitter, LinkedIn, Facebook, Instagram, TikTok, YouTube, HootSuite, Buffer
257 lines (232 loc) • 9.1 kB
text/typescript
import { RegisterClass } from '@memberjunction/global';
import { YouTubeBaseAction } from '../youtube-base.action';
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
import { BaseAction } from '@memberjunction/actions';
/**
* Action to create a playlist on YouTube
*/
(BaseAction, 'YouTubeCreatePlaylistAction')
export class YouTubeCreatePlaylistAction extends YouTubeBaseAction {
/**
* Create a playlist on YouTube
*/
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
const { Params, ContextUser } = params;
try {
// Initialize OAuth
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
if (!companyIntegrationId) {
throw new Error('CompanyIntegrationID is required');
}
const initialized = await this.initializeOAuth(companyIntegrationId);
if (!initialized) {
throw new Error('Failed to initialize YouTube OAuth connection');
}
// Extract parameters
const title = this.getParamValue(Params, 'Title');
const description = this.getParamValue(Params, 'Description');
const privacyStatus = this.getParamValue(Params, 'PrivacyStatus') || 'private';
const tags = this.getParamValue(Params, 'Tags');
const defaultLanguage = this.getParamValue(Params, 'DefaultLanguage');
const videoIds = this.getParamValue(Params, 'VideoIDs');
// Validate required parameters
if (!title) {
throw new Error('Title is required for playlist creation');
}
// Create playlist
const playlistData = {
snippet: {
title: title,
description: description || '',
tags: tags || [],
defaultLanguage: defaultLanguage || 'en'
},
status: {
privacyStatus: privacyStatus
}
};
const playlistResponse = await this.makeYouTubeRequest<any>(
'/playlists',
'POST',
playlistData,
{
part: 'snippet,status'
},
ContextUser
);
const playlistId = playlistResponse.id;
// Add videos to playlist if provided
let addedVideos: any[] = [];
if (videoIds && videoIds.length > 0) {
addedVideos = await this.addVideosToPlaylist(playlistId, videoIds, ContextUser);
}
// Get full playlist details
const playlistDetails = await this.makeYouTubeRequest<any>(
'/playlists',
'GET',
undefined,
{
part: 'snippet,status,contentDetails',
id: playlistId
},
ContextUser
);
const playlist = playlistDetails.items[0];
// Prepare result
const result = {
playlistId: playlist.id,
playlistUrl: `https://www.youtube.com/playlist?list=${playlist.id}`,
title: playlist.snippet.title,
description: playlist.snippet.description,
tags: playlist.snippet.tags,
privacyStatus: playlist.status.privacyStatus,
itemCount: playlist.contentDetails.itemCount,
channelId: playlist.snippet.channelId,
channelTitle: playlist.snippet.channelTitle,
publishedAt: playlist.snippet.publishedAt,
thumbnails: playlist.snippet.thumbnails,
videosAdded: addedVideos.length,
videoDetails: addedVideos,
quotaCost: this.getQuotaCost('playlists.insert') + (addedVideos.length * this.getQuotaCost('playlistItems.insert'))
};
// Update output parameters
const outputParams = [...Params];
const playlistDetailsParam = outputParams.find(p => p.Name === 'PlaylistDetails');
if (playlistDetailsParam) playlistDetailsParam.Value = result;
const playlistIdParam = outputParams.find(p => p.Name === 'PlaylistID');
if (playlistIdParam) playlistIdParam.Value = playlistId;
const playlistUrlParam = outputParams.find(p => p.Name === 'PlaylistURL');
if (playlistUrlParam) playlistUrlParam.Value = result.playlistUrl;
return {
Success: true,
ResultCode: 'SUCCESS',
Message: `Playlist created successfully with ${addedVideos.length} videos: ${result.playlistUrl}`,
Params: outputParams
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
return {
Success: false,
ResultCode: this.getErrorCode(errorMessage),
Message: `Failed to create playlist: ${errorMessage}`,
Params
};
}
}
/**
* Add videos to a playlist
*/
private async addVideosToPlaylist(playlistId: string, videoIds: string[], contextUser?: any): Promise<any[]> {
const addedVideos: any[] = [];
for (let i = 0; i < videoIds.length; i++) {
const videoId = videoIds[i];
try {
const playlistItem = {
snippet: {
playlistId: playlistId,
position: i,
resourceId: {
kind: 'youtube#video',
videoId: videoId
}
}
};
const response = await this.makeYouTubeRequest<any>(
'/playlistItems',
'POST',
playlistItem,
{
part: 'snippet'
},
contextUser
);
addedVideos.push({
videoId: videoId,
position: response.snippet.position,
addedAt: response.snippet.publishedAt,
playlistItemId: response.id
});
} catch (error) {
// Log error but continue adding other videos
console.error(`Failed to add video ${videoId} to playlist:`, error);
addedVideos.push({
videoId: videoId,
position: i,
error: error.message
});
}
}
return addedVideos;
}
/**
* Get error code from error message
*/
private getErrorCode(message: string): string {
if (message.includes('quota')) return 'QUOTA_EXCEEDED';
if (message.includes('401') || message.includes('unauthorized')) return 'INVALID_TOKEN';
if (message.includes('403') || message.includes('forbidden')) return 'INSUFFICIENT_PERMISSIONS';
if (message.includes('404')) return 'NOT_FOUND';
if (message.includes('rate limit')) return 'RATE_LIMIT';
return 'ERROR';
}
/**
* Define the parameters this action expects
*/
public get Params(): ActionParam[] {
const baseParams = this.commonSocialParams;
const specificParams: ActionParam[] = [
{
Name: 'Title',
Type: 'Input',
Value: null
},
{
Name: 'Description',
Type: 'Input',
Value: null
},
{
Name: 'PrivacyStatus',
Type: 'Input',
Value: 'private'
},
{
Name: 'Tags',
Type: 'Input',
Value: null
},
{
Name: 'DefaultLanguage',
Type: 'Input',
Value: 'en'
},
{
Name: 'VideoIDs',
Type: 'Input',
Value: null
},
{
Name: 'PlaylistDetails',
Type: 'Output',
Value: null
},
{
Name: 'PlaylistID',
Type: 'Output',
Value: null
},
{
Name: 'PlaylistURL',
Type: 'Output',
Value: null
}
];
return [...baseParams, ...specificParams];
}
/**
* Metadata about this action
*/
public get Description(): string {
return 'Creates a YouTube playlist and optionally adds videos to it';
}
}