feat:영상 파일 GCS 저장 및 삭제 연동
- VideoGenerationJob: 최종 합성 후 GCS 업로드, gcs_path 저장 - Veo3Controller: download/preview GCS 서명URL 사용, destroy GCS 파일 삭제 - VideoGeneration 모델: gcs_path fillable 추가 - GCS 불가 시 로컬 파일로 폴백 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,8 +5,10 @@
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Jobs\VideoGenerationJob;
|
||||
use App\Models\VideoGeneration;
|
||||
use App\Services\GoogleCloudStorageService;
|
||||
use App\Services\Video\GeminiScriptService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\View\View;
|
||||
@@ -15,7 +17,8 @@
|
||||
class Veo3Controller extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private readonly GeminiScriptService $geminiService
|
||||
private readonly GeminiScriptService $geminiService,
|
||||
private readonly GoogleCloudStorageService $gcsService
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -164,7 +167,7 @@ public function status(int $id): JsonResponse
|
||||
/**
|
||||
* 완성 영상 다운로드
|
||||
*/
|
||||
public function download(int $id): BinaryFileResponse|JsonResponse
|
||||
public function download(int $id): BinaryFileResponse|RedirectResponse|JsonResponse
|
||||
{
|
||||
$video = VideoGeneration::findOrFail($id);
|
||||
|
||||
@@ -172,6 +175,15 @@ public function download(int $id): BinaryFileResponse|JsonResponse
|
||||
return response()->json(['message' => '아직 영상이 완성되지 않았습니다.'], 404);
|
||||
}
|
||||
|
||||
// GCS 서명URL로 리다이렉트
|
||||
if ($video->gcs_path && $this->gcsService->isAvailable()) {
|
||||
$signedUrl = $this->gcsService->getSignedUrl($video->gcs_path, 30);
|
||||
if ($signedUrl) {
|
||||
return redirect()->away($signedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// 로컬 파일 폴백
|
||||
if (! file_exists($video->output_path)) {
|
||||
return response()->json(['message' => '영상 파일을 찾을 수 없습니다.'], 404);
|
||||
}
|
||||
@@ -187,10 +199,19 @@ public function download(int $id): BinaryFileResponse|JsonResponse
|
||||
/**
|
||||
* 영상 미리보기 (스트리밍)
|
||||
*/
|
||||
public function preview(int $id): Response|JsonResponse
|
||||
public function preview(int $id): Response|RedirectResponse|JsonResponse
|
||||
{
|
||||
$video = VideoGeneration::findOrFail($id);
|
||||
|
||||
// GCS 서명URL로 리다이렉트
|
||||
if ($video->gcs_path && $this->gcsService->isAvailable()) {
|
||||
$signedUrl = $this->gcsService->getSignedUrl($video->gcs_path, 60);
|
||||
if ($signedUrl) {
|
||||
return redirect()->away($signedUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// 로컬 파일 폴백
|
||||
if (! $video->output_path || ! file_exists($video->output_path)) {
|
||||
return response()->json(['message' => '영상 파일을 찾을 수 없습니다.'], 404);
|
||||
}
|
||||
@@ -237,6 +258,11 @@ public function destroy(Request $request): JsonResponse
|
||||
|
||||
$deleted = 0;
|
||||
foreach ($videos as $video) {
|
||||
// GCS 파일 삭제
|
||||
if ($video->gcs_path && $this->gcsService->isAvailable()) {
|
||||
$this->gcsService->delete($video->gcs_path);
|
||||
}
|
||||
|
||||
// 로컬 작업 디렉토리 삭제 (클립, 나레이션, 최종 영상 등)
|
||||
$workDir = storage_path("app/video_gen/{$video->id}");
|
||||
if (is_dir($workDir)) {
|
||||
|
||||
Reference in New Issue
Block a user