mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
Includes a Dockerfile for building the application image and an INSTALLATION.md file detailing the setup process, prerequisites, and helpful commands for managing the application on a private server. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ae4037a0-2a6f-4530-9bac-79b543286bda Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/397bca8c-984f-43ff-841a-10897aeb8140/ae4037a0-2a6f-4530-9bac-79b543286bda/ds3R7vP
103 lines
3.0 KiB
TypeScript
103 lines
3.0 KiB
TypeScript
import sharp from "sharp";
|
|
import { randomUUID } from "crypto";
|
|
import path from "path";
|
|
import fs from "fs/promises";
|
|
|
|
interface CropDimensions {
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
interface ProcessedImages {
|
|
facebookFeed: string;
|
|
instagramFeed: string;
|
|
instagramStory: string;
|
|
}
|
|
|
|
const CROP_FORMATS = {
|
|
facebookFeed: { width: 1200, height: 630 } as CropDimensions,
|
|
instagramFeed: { width: 1080, height: 1080 } as CropDimensions,
|
|
instagramStory: { width: 1080, height: 1920 } as CropDimensions,
|
|
};
|
|
|
|
export class ImageProcessor {
|
|
private uploadsDir: string;
|
|
|
|
constructor() {
|
|
this.uploadsDir = path.join(process.cwd(), "uploads");
|
|
this.ensureUploadsDirExists();
|
|
}
|
|
|
|
private async ensureUploadsDirExists() {
|
|
try {
|
|
await fs.access(this.uploadsDir);
|
|
} catch {
|
|
await fs.mkdir(this.uploadsDir, { recursive: true });
|
|
}
|
|
}
|
|
|
|
async processImage(buffer: Buffer, originalFilename: string): Promise<ProcessedImages> {
|
|
const fileExt = path.extname(originalFilename);
|
|
const baseId = randomUUID();
|
|
|
|
const processedImages: ProcessedImages = {
|
|
facebookFeed: "",
|
|
instagramFeed: "",
|
|
instagramStory: "",
|
|
};
|
|
|
|
// Process Facebook Feed (1200x630)
|
|
const fbFeedFilename = `${baseId}-fb-feed${fileExt}`;
|
|
const fbFeedPath = path.join(this.uploadsDir, fbFeedFilename);
|
|
await sharp(buffer)
|
|
.resize(CROP_FORMATS.facebookFeed.width, CROP_FORMATS.facebookFeed.height, {
|
|
fit: "cover",
|
|
position: "center",
|
|
})
|
|
.toFile(fbFeedPath);
|
|
processedImages.facebookFeed = `/uploads/${fbFeedFilename}`;
|
|
|
|
// Process Instagram Feed (1080x1080)
|
|
const igFeedFilename = `${baseId}-ig-feed${fileExt}`;
|
|
const igFeedPath = path.join(this.uploadsDir, igFeedFilename);
|
|
await sharp(buffer)
|
|
.resize(CROP_FORMATS.instagramFeed.width, CROP_FORMATS.instagramFeed.height, {
|
|
fit: "cover",
|
|
position: "center",
|
|
})
|
|
.toFile(igFeedPath);
|
|
processedImages.instagramFeed = `/uploads/${igFeedFilename}`;
|
|
|
|
// Process Instagram Story (1080x1920)
|
|
const igStoryFilename = `${baseId}-ig-story${fileExt}`;
|
|
const igStoryPath = path.join(this.uploadsDir, igStoryFilename);
|
|
await sharp(buffer)
|
|
.resize(CROP_FORMATS.instagramStory.width, CROP_FORMATS.instagramStory.height, {
|
|
fit: "cover",
|
|
position: "center",
|
|
})
|
|
.toFile(igStoryPath);
|
|
processedImages.instagramStory = `/uploads/${igStoryFilename}`;
|
|
|
|
return processedImages;
|
|
}
|
|
|
|
async saveOriginalFile(buffer: Buffer, filename: string): Promise<string> {
|
|
const uniqueFilename = `${randomUUID()}-${filename}`;
|
|
const filePath = path.join(this.uploadsDir, uniqueFilename);
|
|
await fs.writeFile(filePath, buffer);
|
|
return `/uploads/${uniqueFilename}`;
|
|
}
|
|
|
|
async deleteFile(filePath: string): Promise<void> {
|
|
try {
|
|
const fullPath = path.join(process.cwd(), filePath);
|
|
await fs.unlink(fullPath);
|
|
} catch (error) {
|
|
console.error("Error deleting file:", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const imageProcessor = new ImageProcessor();
|