feat: 숏폼 자막 완료 텔레그램 알림 추가
This commit is contained in:
parent
504d0f09d5
commit
f51cab471e
@ -1,5 +1,6 @@
|
||||
package com.hlab.yanalyst.domain.shortform;
|
||||
|
||||
import com.hlab.yanalyst.global.notify.TelegramNotifier;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
@ -29,6 +30,7 @@ public class ShortformSubtitleService {
|
||||
|
||||
private final ShortformJobRepository jobRepository;
|
||||
private final ShortformWhisperService whisperService;
|
||||
private final TelegramNotifier telegramNotifier;
|
||||
|
||||
@Value("${ytdlp.bin:yt-dlp}")
|
||||
private String ytdlpBin;
|
||||
@ -52,18 +54,47 @@ public class ShortformSubtitleService {
|
||||
String vtt = collectOrTranscribe(jobId, job.getVideoId());
|
||||
ShortformJob current = jobRepository.findById(jobId).orElse(null);
|
||||
if (current == null) return;
|
||||
if (vtt == null) current.markSubtitleUnavailable("한국어 공식/자동 자막이 없습니다");
|
||||
if (vtt == null) current.markSubtitleUnavailable("YouTube/Whisper 자막을 생성하지 못했습니다");
|
||||
else current.storeSubtitle(vtt);
|
||||
jobRepository.save(current);
|
||||
if (vtt == null) notifyFailure(current, current.getSubtitleError());
|
||||
else notifyReady(current);
|
||||
} catch (Exception e) {
|
||||
log.warn("숏폼 큐 자막 수집 실패: jobId={}, videoId={}", jobId, job.getVideoId(), e);
|
||||
jobRepository.findById(jobId).ifPresent(current -> {
|
||||
current.markSubtitleFailed(e.getMessage());
|
||||
jobRepository.save(current);
|
||||
notifyFailure(current, current.getSubtitleError());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyReady(ShortformJob job) {
|
||||
telegramNotifier.sendMessage("✅ <b>숏폼 자막 생성 완료</b>\n"
|
||||
+ "분류: " + categoryLabel(job) + "\n"
|
||||
+ "영상: <code>" + job.getVideoId() + "</code>\n"
|
||||
+ "<a href=\"https://h-lab.tolag.shop/shortform?category="
|
||||
+ job.categoryOrDefault().name() + "\">숏폼 큐에서 확인</a>");
|
||||
}
|
||||
|
||||
private void notifyFailure(ShortformJob job, String reason) {
|
||||
telegramNotifier.sendMessage("❌ <b>숏폼 자막 생성 실패</b>\n"
|
||||
+ "분류: " + categoryLabel(job) + "\n"
|
||||
+ "영상: <code>" + job.getVideoId() + "</code>\n"
|
||||
+ "사유: " + escapeHtml(reason) + "\n"
|
||||
+ "<a href=\"https://h-lab.tolag.shop/shortform?category="
|
||||
+ job.categoryOrDefault().name() + "\">숏폼 큐에서 확인</a>");
|
||||
}
|
||||
|
||||
private static String categoryLabel(ShortformJob job) {
|
||||
return job.categoryOrDefault() == ShortformCategory.POLITICS ? "정치" : "예능";
|
||||
}
|
||||
|
||||
private static String escapeHtml(String value) {
|
||||
if (value == null || value.isBlank()) return "알 수 없는 오류";
|
||||
return value.replace("&", "&").replace("<", "<").replace(">", ">");
|
||||
}
|
||||
|
||||
String collectOrTranscribe(Long jobId, String videoId) throws IOException, InterruptedException {
|
||||
try {
|
||||
String vtt = collectWithRetry(videoId);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.hlab.yanalyst.domain.shortform;
|
||||
|
||||
import com.hlab.yanalyst.global.notify.TelegramNotifier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Path;
|
||||
@ -37,7 +38,8 @@ class ShortformSubtitleServiceTest {
|
||||
@Test
|
||||
void retriesOnceWhenFirstCollectionHasNoSubtitle() throws Exception {
|
||||
ShortformSubtitleService service = spy(new ShortformSubtitleService(
|
||||
mock(ShortformJobRepository.class), mock(ShortformWhisperService.class)));
|
||||
mock(ShortformJobRepository.class), mock(ShortformWhisperService.class),
|
||||
mock(TelegramNotifier.class)));
|
||||
doReturn(null, "WEBVTT\n").when(service).collect("gDfGqRDubCg");
|
||||
|
||||
assertThat(service.collectWithRetry("gDfGqRDubCg")).isEqualTo("WEBVTT\n");
|
||||
@ -48,7 +50,8 @@ class ShortformSubtitleServiceTest {
|
||||
void fallsBackToWhisperWhenYoutubeHasNoSubtitle() throws Exception {
|
||||
ShortformJobRepository repository = mock(ShortformJobRepository.class);
|
||||
ShortformWhisperService whisperService = mock(ShortformWhisperService.class);
|
||||
ShortformSubtitleService service = spy(new ShortformSubtitleService(repository, whisperService));
|
||||
ShortformSubtitleService service = spy(new ShortformSubtitleService(
|
||||
repository, whisperService, mock(TelegramNotifier.class)));
|
||||
doReturn(null).when(service).collectWithRetry("gDfGqRDubCg");
|
||||
when(whisperService.transcribe("gDfGqRDubCg")).thenReturn("WEBVTT\n");
|
||||
|
||||
@ -64,13 +67,15 @@ class ShortformSubtitleServiceTest {
|
||||
"gDfGqRDubCg",
|
||||
ShortformCategory.ENTERTAINMENT);
|
||||
when(repository.findById(1L)).thenReturn(Optional.of(job));
|
||||
TelegramNotifier telegramNotifier = mock(TelegramNotifier.class);
|
||||
ShortformSubtitleService service = spy(new ShortformSubtitleService(
|
||||
repository, mock(ShortformWhisperService.class)));
|
||||
repository, mock(ShortformWhisperService.class), telegramNotifier));
|
||||
doReturn("WEBVTT\n").when(service).collectOrTranscribe(1L, "gDfGqRDubCg");
|
||||
|
||||
service.collectAsync(1L);
|
||||
|
||||
assertThat(job.getSubtitleStatus()).isEqualTo(SubtitleStatus.READY);
|
||||
assertThat(job.getSubtitleVtt()).isEqualTo("WEBVTT\n");
|
||||
verify(telegramNotifier).sendMessage(org.mockito.ArgumentMatchers.contains("자막 생성 완료"));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user