generated from fahricansecer/boilerplate-be
92 lines
3.3 KiB
C#
92 lines
3.3 KiB
C#
using System.Diagnostics;
|
||
using System.Text.Json;
|
||
using Microsoft.Extensions.Logging;
|
||
using SaasMediaWorker.Models;
|
||
|
||
namespace SaasMediaWorker.Services;
|
||
|
||
public class RemotionService
|
||
{
|
||
private readonly ILogger<RemotionService> _logger;
|
||
|
||
public RemotionService(ILogger<RemotionService> logger)
|
||
{
|
||
_logger = logger;
|
||
}
|
||
|
||
public async Task<string> RenderVideoAsync(
|
||
string projectId,
|
||
string projectDir,
|
||
List<ScenePayload> scenes,
|
||
List<GeneratedMediaFile> generatedMedia,
|
||
string? musicPath,
|
||
int targetDurationSeconds,
|
||
string visualEffect,
|
||
CancellationToken ct)
|
||
{
|
||
_logger.LogInformation("🎬 Remotion render başlatılıyor — Project: {Id}", projectId);
|
||
|
||
// Remotion projesinin kök dizini (media-worker içindeki remotion klasörü)
|
||
var remotionDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "remotion");
|
||
|
||
// Props JSON dosyasını hazırla
|
||
var props = new
|
||
{
|
||
musicPath = musicPath,
|
||
visualEffect = visualEffect,
|
||
scenes = scenes.Select(s => new
|
||
{
|
||
imagePath = s.ImagePath,
|
||
audioPath = generatedMedia.FirstOrDefault(m => m.SceneOrder == s.Order && m.Type == MediaFileType.AudioNarration)?.LocalPath,
|
||
ambientPath = generatedMedia.FirstOrDefault(m => m.SceneOrder == s.Order && m.Type == MediaFileType.AudioAmbient)?.LocalPath,
|
||
subtitle = s.SubtitleText,
|
||
durationInFrames = (int)(s.Duration * 30) // 30 FPS varsayımı
|
||
}).ToList()
|
||
};
|
||
|
||
var propsPath = Path.Combine(projectDir, "remotion-props.json");
|
||
await File.WriteAllTextAsync(propsPath, JsonSerializer.Serialize(props), ct);
|
||
|
||
// Final çıktı yolu
|
||
var outputPath = Path.Combine(projectDir, $"final_{projectId}.mp4");
|
||
|
||
// npx remotion render src/index.ts MainVideo output.mp4 --props props.json
|
||
var arguments = $"remotion render src/index.ts MainVideo \"{outputPath}\" --props=\"{propsPath}\"";
|
||
|
||
_logger.LogInformation("Çalıştırılıyor: npx {Args} (Dizin: {Dir})", arguments, remotionDir);
|
||
|
||
var processInfo = new ProcessStartInfo
|
||
{
|
||
FileName = "npx",
|
||
Arguments = arguments,
|
||
WorkingDirectory = remotionDir,
|
||
RedirectStandardOutput = true,
|
||
RedirectStandardError = true,
|
||
UseShellExecute = false,
|
||
CreateNoWindow = true
|
||
};
|
||
|
||
using var process = Process.Start(processInfo);
|
||
if (process == null)
|
||
throw new InvalidOperationException("Remotion process başlatılamadı.");
|
||
|
||
var outputTask = process.StandardOutput.ReadToEndAsync();
|
||
var errorTask = process.StandardError.ReadToEndAsync();
|
||
|
||
await process.WaitForExitAsync(ct);
|
||
|
||
var output = await outputTask;
|
||
var error = await errorTask;
|
||
|
||
if (process.ExitCode != 0)
|
||
{
|
||
_logger.LogError("Remotion render hatası. ExitCode: {Code}\nOutput: {Output}\nError: {Error}",
|
||
process.ExitCode, output, error);
|
||
throw new Exception($"Remotion render başarısız oldu. Hata: {error}");
|
||
}
|
||
|
||
_logger.LogInformation("✅ Remotion render tamamlandı: {Path}", outputPath);
|
||
return outputPath;
|
||
}
|
||
}
|