diff --git a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformController.java b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformController.java index ccd306f..4208411 100644 --- a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformController.java +++ b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformController.java @@ -50,6 +50,11 @@ public class ShortformController { return ApiResponse.ok(shortformService.reset(id)); } + @PostMapping("/jobs/{id}/complete") + public ApiResponse complete(@PathVariable Long id) { + return ApiResponse.ok(shortformService.completeCopyWorkflow(id)); + } + @PostMapping("/jobs/{id}/subtitles/retry") public ApiResponse retrySubtitles(@PathVariable Long id) { shortformService.retrySubtitle(id); diff --git a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformJob.java b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformJob.java index 2fbf119..f3e4817 100644 --- a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformJob.java +++ b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformJob.java @@ -154,6 +154,14 @@ public class ShortformJob { this.completedAt = LocalDateTime.now(); } + /** URL 또는 자막을 외부 작업 도구로 복사한 큐 작업을 완료 처리한다. */ + public void completeCopyWorkflow() { + this.status = ShortformJobStatus.DONE; + if (this.completedAt == null) { + this.completedAt = LocalDateTime.now(); + } + } + /** * 결과를 비우고 다시 대기 상태로 되돌린다. 등록 정보(URL·videoId·등록시각)는 유지하므로 * 삭제 후 재등록할 필요가 없고, 큐 스킬이 PENDING 만 집어가므로 그대로 다시 실행된다. diff --git a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformService.java b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformService.java index cee4063..771aba8 100644 --- a/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformService.java +++ b/src/main/java/com/hlab/yanalyst/domain/shortform/ShortformService.java @@ -133,6 +133,14 @@ public class ShortformService { .orElseThrow(() -> new IllegalArgumentException("작업이 없습니다: " + jobId)); } + @Transactional + public JobDetail completeCopyWorkflow(Long jobId) { + ShortformJob job = jobRepository.findById(jobId) + .orElseThrow(() -> new IllegalArgumentException("작업이 없습니다: " + jobId)); + job.completeCopyWorkflow(); + return JobDetail.from(job); + } + @Transactional public void delete(Long jobId) { jobRepository.deleteById(jobId); diff --git a/src/main/resources/templates/shortform.html b/src/main/resources/templates/shortform.html index 79d5b73..389e65b 100644 --- a/src/main/resources/templates/shortform.html +++ b/src/main/resources/templates/shortform.html @@ -182,8 +182,7 @@ e.stopPropagation(); await navigator.clipboard.writeText(decodeURIComponent(btn.dataset.copy)); if (btn.hasAttribute('data-complete-on-copy')) { - btn.textContent = '완료'; - btn.disabled = true; + await completeCopiedJob(id, el, btn); } else { btn.textContent = '복사됨!'; setTimeout(() => btn.textContent = label, 1200); @@ -195,8 +194,7 @@ subtitleButton.onclick = async (e) => { e.stopPropagation(); await navigator.clipboard.writeText(detail.subtitleVtt); - subtitleButton.textContent = '완료'; - subtitleButton.disabled = true; + await completeCopiedJob(id, el, subtitleButton); }; } } @@ -205,6 +203,17 @@ return (s || '').replace(/&/g, '&').replace(//g, '>'); } + async function completeCopiedJob(id, card, button) { + await api('/api/shortform/jobs/' + id + '/complete', { method: 'POST' }); + button.textContent = '완료'; + button.disabled = true; + const badge = card.querySelector('.sf-badge'); + if (badge) { + badge.className = 'sf-badge DONE'; + badge.textContent = 'DONE'; + } + } + function clipHtml(c) { return `
@@ -301,8 +310,7 @@ button.onclick = async (e) => { e.stopPropagation(); await navigator.clipboard.writeText(detail.subtitleVtt); - button.textContent = '완료'; - button.disabled = true; + await completeCopiedJob(id, card, button); }; } diff --git a/src/test/java/com/hlab/yanalyst/domain/shortform/ShortformJobResetTest.java b/src/test/java/com/hlab/yanalyst/domain/shortform/ShortformJobResetTest.java index 26c789d..113a60a 100644 --- a/src/test/java/com/hlab/yanalyst/domain/shortform/ShortformJobResetTest.java +++ b/src/test/java/com/hlab/yanalyst/domain/shortform/ShortformJobResetTest.java @@ -69,4 +69,14 @@ class ShortformJobResetTest { assertThat(job.getTitle()).isEqualTo("새 클립"); assertThat(job.getRawOutput()).isEqualTo("새 Output"); } + + @Test + void 복사_워크플로를_완료하면_DONE으로_변경된다() { + ShortformJob job = ShortformJob.create("https://youtu.be/abc12345678", "abc12345678"); + + job.completeCopyWorkflow(); + + assertThat(job.getStatus()).isEqualTo(ShortformJobStatus.DONE); + assertThat(job.getCompletedAt()).isNotNull(); + } }