디글 클래식처럼 한 채널에 여러 프로그램이 섞인 경우 특정 프로그램만
피드에 수집하기 위한 설계. Channel에 feed_title_filter 컬럼을 추가하고
공백 무시 부분일치 OR 매칭으로 수집 단계에서 거른다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Opal이 title_top 같은 값에 따옴표를 이스케이프 없이 뱉으면 파서의
Jackson readTree가 던져서 status=FAILED, clips=0이 된다. 같은 JSON이
캡컷 구간 JSON 붙여넣기로도 들어가므로 저장과 영상 생성이 둘 다 막힌다.
저장 전에 파싱을 시도하고, 깨졌으면 fix-opal-json.ps1로 문자열 값
안쪽 따옴표만 이스케이프한 뒤 재검증한다. 그래도 안 되면 저장하지
않고 PENDING으로 남긴다. 정상 JSON에는 아무 변화가 없다.
캡컷 방식 선택도 모드별로 갈랐다 - 1단계는 구간 JSON(wpaste),
풀버전은 오팔 JSON(paste).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"숏폼 돌려줘"가 이제 1단계 앱으로 돌아간다. 풀버전은 "풀버전으로
돌려줘"로 명시할 때만 쓴다.
작업 저장이 DONE 되면 캡컷 에이전트(127.0.0.1:8001)의 자동 탭
구간 JSON 방식으로 유튜브 URL과 candidates JSON을 넣고 영상 생성을
시작만 시킨다. 완료를 기다리지 않고 바로 다음 작업의 Opal 실행으로
넘어간다. 서버가 analysis_id별로 독립 처리해 동시 실행이 가능하고,
작업마다 새 탭을 써서 앞 실행의 화면 상태가 덮이지 않게 한다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
피드·인물 수집에서 새로 담긴 영상이 업로드 24시간(골든타임) 이내면
텔레그램으로 알림을 발송한다. 신규 insert만 대상이라 같은 영상이
두 번 울리지 않고, 경쟁(RIVAL) 채널 영상은 알림에서 제외한다.
기존 TelegramNotifier(hlab.notify.telegram) 재사용 — 미설정 시 no-op.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- SKILL.md에 모드 선택 표(풀버전/1단계) 및 1단계 전용 절차 추가
("1단계만 돌려줘" → candidates JSON 앱으로 실행·저장)
- 오늘 실전에서 확인한 절차 개선 반영: application-local.yml 복사,
브라우저 fetch 차단(HTTPS→HTTP) 우회, PS 5.1 인코딩 주의
- docs/shortform-queue-skill-portable.md: 다른 PC에서 md 하나로
스킬 등록·전제조건 점검이 가능한 자기완결 가이드
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
피드 수집 필터를 쇼츠/롱폼 구분에서 최소 길이(초) 기준으로 교체.
기본 600초(10분) — FEED_MIN_DURATION_SEC 로 조정 가능.
화면 조회에도 같은 하한을 적용해 이미 담긴 10분 미만 영상도
소스·경쟁 탭에서 바로 사라진다. 길이 필터 라벨(공식클립 10~15분)도 정리.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
인물 추적은 65초 컷으로 쇼츠를 걸렀지만 유튜브 쇼츠가 최대 3분까지
허용되면서 1~3분짜리 쇼츠가 통과해 인물 탭에 들어왔다.
수집(PersonPicks)과 조회(feedByPerson) 모두 180초 컷으로 올려
이미 담긴 1~3분 영상도 탭에서 사라지게 했다.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
결과가 잘못 나왔을 때 지금은 작업을 통째로 삭제하고 URL을 다시 등록해야 했다.
등록 이력도 같이 날아간다.
큐 스킬이 status=PENDING 인 작업만 집어가므로, 결과만 비우고 PENDING 으로
되돌리면 그대로 재실행 대상이 된다.
- POST /api/shortform/jobs/{id}/reset — rawOutput·step1Output·clips·title·
completedAt 을 비우고 PENDING 으로. youtubeUrl·videoId·등록시각은 유지한다.
- 화면: PENDING 이 아닌 카드에만 되돌리기 버튼(확인창 포함). 결과가 삭제되므로
무엇이 지워지고 무엇이 남는지 문구에 명시했다.
- FAILED 재시도에 특히 필요했다 — 파싱 실패한 작업을 되살릴 방법이 아예 없었다.
fix: Mockito self-attach 실패로 목 기반 테스트 6건이 깨지던 문제
내 변경과 무관하게 환경에서 깨져 있었다(변경을 치운 깨끗한 트리에서도 동일 실패).
Mockito 가 JVM 에 self-attach 를 시도하다 실패하면 "Could not initialize plugin:
MockMaker" 로 DashboardServiceTest·YoutubeCommentServiceTest 가 전부 죽는다.
JDK 21+ 는 self-attach 를 경고하고 이후 버전에서 막으므로, 권장 방식대로
mockitoAgent 설정을 만들어 -javaagent 로 명시 지정했다. 116건 전부 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
썸네일·제목을 누르면 YouTube 새 탭으로 나가던 걸 레이어 팝업 재생으로 바꿨다.
쇼츠는 세로(9:16), 롱폼은 가로(16:9)로 비율을 맞추고, 팝업 안에 숏폼 큐 등록과
YouTube 열기를 함께 뒀다. Escape·배경 클릭으로 닫히고 닫을 때 재생이 멈춘다.
임베드를 막아둔 채널이 많다는 걸 실측했다 — 소재 원본 9건 중 4건이 차단이고
채널 단위로 갈린다(짠한형 전부 차단, 뜬뜬·스프 전부 가능). 그대로 두면 절반이
"동영상을 재생할 수 없음" 화면을 보게 되므로:
- 수집할 때 videos.list 에 status 파트를 붙여 embeddable 을 저장한다(쿼터 동일).
- 차단된 영상은 팝업 대신 바로 YouTube 새 탭으로 연다.
- 차단 영상 썸네일에 외부링크 아이콘을 띄워 눌렀을 때 나가는 걸 예고한다.
- embeddable 이 null(미수집)이면 일단 재생을 시도한다 — 팝업 안에 YouTube 링크가
있어 막혀도 빠져나갈 수 있다.
브라우저에서 확인: 재생 가능 영상은 팝업에서 실제 재생됐고(썸네일·제목 클릭 모두),
차단 채널 카드에만 외부링크 아이콘이 붙었다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>