mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
Implement functionality for uploading, applying, and deleting custom logos as overlays on images, along with backend processing and UI updates. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 91999614-5187-4902-b7a1-bf9e372de9c8 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/JgqpaNl
193 lines
6.0 KiB
TypeScript
193 lines
6.0 KiB
TypeScript
import { v2 as cloudinary } from 'cloudinary';
|
|
import { storage } from '../storage';
|
|
|
|
class CloudinaryService {
|
|
async uploadMedia(
|
|
buffer: Buffer,
|
|
fileName: string,
|
|
userId: string,
|
|
mimeType: string
|
|
): Promise<{
|
|
publicId: string;
|
|
originalUrl: string;
|
|
facebookFeedUrl: string | null;
|
|
instagramFeedUrl: string | null;
|
|
instagramStoryUrl: string | null;
|
|
}> {
|
|
// Get any available Cloudinary config (shared across all users)
|
|
const config = await storage.getAnyCloudinaryConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('Cloudinary configuration not found. Please ask an administrator to configure Cloudinary in Settings first.');
|
|
}
|
|
|
|
// Configure Cloudinary with user's credentials
|
|
cloudinary.config({
|
|
cloud_name: config.cloudName,
|
|
api_key: config.apiKey,
|
|
api_secret: config.apiSecret,
|
|
secure: true,
|
|
});
|
|
|
|
const isVideo = mimeType.startsWith('video/');
|
|
|
|
// Define eager transformations for images (generated during upload)
|
|
const eagerTransformations = !isVideo ? [
|
|
{ width: 1080, height: 1080, crop: 'fill', gravity: 'center' }, // Facebook Feed (square, no borders)
|
|
{ width: 1080, height: 1080, crop: 'pad', gravity: 'center', background: 'auto' }, // Instagram Feed
|
|
{ width: 1080, height: 1920, crop: 'pad', gravity: 'center', background: 'auto' } // Instagram Story
|
|
] : undefined;
|
|
|
|
// Upload to Cloudinary with eager transformations
|
|
const uploadResult = await new Promise<any>((resolve, reject) => {
|
|
const uploadStream = cloudinary.uploader.upload_stream(
|
|
{
|
|
folder: 'social-flow',
|
|
public_id: `${Date.now()}-${fileName.replace(/\.[^/.]+$/, '')}`,
|
|
resource_type: isVideo ? 'video' : 'image',
|
|
eager: eagerTransformations,
|
|
eager_async: false, // Generate transformations immediately
|
|
},
|
|
(error, result) => {
|
|
if (error) reject(error);
|
|
else resolve(result);
|
|
}
|
|
);
|
|
|
|
uploadStream.end(buffer);
|
|
});
|
|
|
|
const publicId = uploadResult.public_id;
|
|
const originalUrl = uploadResult.secure_url;
|
|
|
|
// Extract eager transformation URLs (generated by Cloudinary during upload)
|
|
let facebookFeedUrl = null;
|
|
let instagramFeedUrl = null;
|
|
let instagramStoryUrl = null;
|
|
|
|
if (!isVideo && uploadResult.eager && uploadResult.eager.length === 3) {
|
|
facebookFeedUrl = uploadResult.eager[0].secure_url; // Facebook Feed (1200x630)
|
|
instagramFeedUrl = uploadResult.eager[1].secure_url; // Instagram Feed (1080x1080)
|
|
instagramStoryUrl = uploadResult.eager[2].secure_url; // Instagram Story (1080x1920)
|
|
}
|
|
|
|
return {
|
|
publicId,
|
|
originalUrl,
|
|
facebookFeedUrl,
|
|
instagramFeedUrl,
|
|
instagramStoryUrl,
|
|
};
|
|
}
|
|
|
|
async deleteMedia(publicId: string, userId: string, mediaType: 'image' | 'video'): Promise<void> {
|
|
// Get any available Cloudinary config (shared across all users)
|
|
const config = await storage.getAnyCloudinaryConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('Cloudinary configuration not found. Please ask an administrator to configure Cloudinary in Settings first.');
|
|
}
|
|
|
|
cloudinary.config({
|
|
cloud_name: config.cloudName,
|
|
api_key: config.apiKey,
|
|
api_secret: config.apiSecret,
|
|
secure: true,
|
|
});
|
|
|
|
await cloudinary.uploader.destroy(publicId, {
|
|
resource_type: mediaType,
|
|
});
|
|
}
|
|
|
|
async uploadStoryImageWithText(buffer: Buffer, originalFileName: string): Promise<string> {
|
|
const config = await storage.getAnyCloudinaryConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('Cloudinary configuration not found. Please ask an administrator to configure Cloudinary in Settings first.');
|
|
}
|
|
|
|
cloudinary.config({
|
|
cloud_name: config.cloudName,
|
|
api_key: config.apiKey,
|
|
api_secret: config.apiSecret,
|
|
secure: true,
|
|
});
|
|
|
|
const uploadResult = await new Promise<any>((resolve, reject) => {
|
|
const uploadStream = cloudinary.uploader.upload_stream(
|
|
{
|
|
folder: 'social-flow/stories',
|
|
public_id: `story-${Date.now()}-${originalFileName.replace(/\.[^/.]+$/, '')}`,
|
|
resource_type: 'image',
|
|
},
|
|
(error, result) => {
|
|
if (error) reject(error);
|
|
else resolve(result);
|
|
}
|
|
);
|
|
|
|
uploadStream.end(buffer);
|
|
});
|
|
|
|
return uploadResult.secure_url;
|
|
}
|
|
|
|
async uploadLogo(buffer: Buffer, fileName: string): Promise<{ publicId: string; url: string }> {
|
|
const config = await storage.getAnyCloudinaryConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('Cloudinary configuration not found. Please ask an administrator to configure Cloudinary in Settings first.');
|
|
}
|
|
|
|
cloudinary.config({
|
|
cloud_name: config.cloudName,
|
|
api_key: config.apiKey,
|
|
api_secret: config.apiSecret,
|
|
secure: true,
|
|
});
|
|
|
|
const uploadResult = await new Promise<any>((resolve, reject) => {
|
|
const uploadStream = cloudinary.uploader.upload_stream(
|
|
{
|
|
folder: 'social-flow/logos',
|
|
public_id: `logo-${Date.now()}-${fileName.replace(/\.[^/.]+$/, '')}`,
|
|
resource_type: 'image',
|
|
},
|
|
(error, result) => {
|
|
if (error) reject(error);
|
|
else resolve(result);
|
|
}
|
|
);
|
|
|
|
uploadStream.end(buffer);
|
|
});
|
|
|
|
return {
|
|
publicId: uploadResult.public_id,
|
|
url: uploadResult.secure_url,
|
|
};
|
|
}
|
|
|
|
async deleteLogo(publicId: string): Promise<void> {
|
|
const config = await storage.getAnyCloudinaryConfig();
|
|
|
|
if (!config) {
|
|
throw new Error('Cloudinary configuration not found. Please ask an administrator to configure Cloudinary in Settings first.');
|
|
}
|
|
|
|
cloudinary.config({
|
|
cloud_name: config.cloudName,
|
|
api_key: config.apiKey,
|
|
api_secret: config.apiSecret,
|
|
secure: true,
|
|
});
|
|
|
|
await cloudinary.uploader.destroy(publicId, {
|
|
resource_type: 'image',
|
|
});
|
|
}
|
|
}
|
|
|
|
export const cloudinaryService = new CloudinaryService();
|