feat(comment-cards): 유튜브 videoId 파서 추가

watch/youtu.be/shorts/embed/순수ID 추출, 단위 테스트 포함

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hehihoho3@gmail.com 2026-06-29 17:04:15 +09:00
parent 4776905745
commit 39e2b42995
2 changed files with 73 additions and 0 deletions

View File

@ -0,0 +1,30 @@
package com.hlab.yanalyst.service;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/** 유튜브 URL 또는 11자리 영상 ID에서 videoId를 추출한다. 실패 시 null. */
public final class YoutubeVideoIdParser {
private static final Pattern BARE = Pattern.compile("^[A-Za-z0-9_-]{11}$");
private static final Pattern[] PATTERNS = {
Pattern.compile("[?&]v=([A-Za-z0-9_-]{11})"),
Pattern.compile("youtu\\.be/([A-Za-z0-9_-]{11})"),
Pattern.compile("/shorts/([A-Za-z0-9_-]{11})"),
Pattern.compile("/embed/([A-Za-z0-9_-]{11})"),
};
private YoutubeVideoIdParser() {}
public static String parse(String input) {
if (input == null) return null;
String s = input.trim();
if (s.isEmpty()) return null;
if (BARE.matcher(s).matches()) return s;
for (Pattern p : PATTERNS) {
Matcher m = p.matcher(s);
if (m.find()) return m.group(1);
}
return null;
}
}

View File

@ -0,0 +1,43 @@
package com.hlab.yanalyst.service;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class YoutubeVideoIdParserTest {
@Test
void parsesWatchUrl() {
assertEquals("dQw4w9WgXcQ",
YoutubeVideoIdParser.parse("https://www.youtube.com/watch?v=dQw4w9WgXcQ"));
}
@Test
void parsesWatchUrlWithExtraParams() {
assertEquals("dQw4w9WgXcQ",
YoutubeVideoIdParser.parse("https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=42s&list=ABC"));
}
@Test
void parsesShortLink() {
assertEquals("dQw4w9WgXcQ",
YoutubeVideoIdParser.parse("https://youtu.be/dQw4w9WgXcQ?si=xyz"));
}
@Test
void parsesShortsLink() {
assertEquals("abc12345678",
YoutubeVideoIdParser.parse("https://www.youtube.com/shorts/abc12345678"));
}
@Test
void parsesBareId() {
assertEquals("dQw4w9WgXcQ", YoutubeVideoIdParser.parse("dQw4w9WgXcQ"));
}
@Test
void returnsNullForGarbage() {
assertNull(YoutubeVideoIdParser.parse("not a youtube link"));
assertNull(YoutubeVideoIdParser.parse(""));
assertNull(YoutubeVideoIdParser.parse(null));
}
}