300 lines
9.1 KiB
Markdown
300 lines
9.1 KiB
Markdown
# 🤝 기여 가이드
|
|
|
|
Video URL Analyzer 프로젝트에 기여해주셔서 감사합니다!
|
|
|
|
## 🚀 시작하기
|
|
|
|
### 1. Repository Fork & Clone
|
|
|
|
```bash
|
|
git clone https://github.com/your-username/video-url-analyzer.git
|
|
cd video-url-analyzer
|
|
```
|
|
|
|
### 2. 개발 환경 설정
|
|
|
|
#### 요구사항
|
|
- **Java**: 17 이상
|
|
- **Gradle**: 7.0 이상
|
|
|
|
#### 의존성 설치
|
|
```bash
|
|
./gradlew build
|
|
```
|
|
|
|
## 🔧 빌드 및 테스트
|
|
|
|
### 빌드
|
|
```bash
|
|
./gradlew clean build
|
|
```
|
|
|
|
### 테스트 실행
|
|
```bash
|
|
./gradlew test
|
|
```
|
|
|
|
### Fat JAR 생성 (의존성 포함)
|
|
```bash
|
|
./gradlew fatJar
|
|
```
|
|
|
|
### 테스트 커버리지 확인
|
|
```bash
|
|
./gradlew test jacocoTestReport
|
|
# 결과: build/reports/jacoco/test/html/index.html
|
|
```
|
|
|
|
## 🏗️ 프로젝트 구조
|
|
|
|
```
|
|
video-url-analyzer/
|
|
├── src/
|
|
│ ├── main/java/com/caliverse/
|
|
│ │ ├── analyzer/
|
|
│ │ │ ├── VideoAnalyzer.java # 메인 클래스
|
|
│ │ │ ├── entity/
|
|
│ │ │ │ └── UrlType.java # URL 타입 Enum
|
|
│ │ │ ├── model/
|
|
│ │ │ │ └── VideoAnalysisResult.java # 결과 모델
|
|
│ │ │ ├── platform/ # 플랫폼별 분석기
|
|
│ │ │ │ ├── PlatformAnalyzer.java
|
|
│ │ │ │ ├── PlatformAnalyzerFactory.java
|
|
│ │ │ │ └── impl/
|
|
│ │ │ │ ├── HttpBasedPlatformAnalyzer.java # HTTP 기반 추상 클래스
|
|
│ │ │ │ ├── NaverTvPlatformAnalyzer.java
|
|
│ │ │ │ ├── KakaoTvPlatformAnalyzer.java
|
|
│ │ │ │ ├── YouTubePlatformAnalyzer.java
|
|
│ │ │ │ ├── VimeoPlatformAnalyzer.java
|
|
│ │ │ │ ├── TikTokPlatformAnalyzer.java
|
|
│ │ │ │ ├── TwitterPlatformAnalyzer.java
|
|
│ │ │ │ ├── WeiboPlatformAnalyzer.java
|
|
│ │ │ │ └── DirectUrlPlatformAnalyzer.java
|
|
│ │ │ └── service/
|
|
│ │ │ └── VideoAnalyzerService.java # 비디오 분석 로직
|
|
│ │ └── global/
|
|
│ │ ├── common/
|
|
│ │ │ ├── CommonConstants.java # 상수 (도메인, API URL, 정규식)
|
|
│ │ │ └── Messages.java # 메시지 관리
|
|
│ │ └── util/ # 유틸리티
|
|
│ │ ├── HttpUtils.java # HTTP 요청 유틸
|
|
│ │ └── UrlParser.java # URL 파싱 유틸
|
|
│ └── test/java/com/caliverse/analyzer/ # 테스트 코드
|
|
│ └── VideoAnalyzerTest.java
|
|
├── build.gradle # 빌드 설정
|
|
├── README.md # 사용자 문서
|
|
└── CONTRIBUTING.md # 이 파일
|
|
```
|
|
|
|
### 주요 컴포넌트
|
|
|
|
#### 1. VideoAnalyzer (메인 API)
|
|
- 비디오 URL 분석의 진입점
|
|
- 플랫폼별 분석기 또는 일반 비디오 분석 선택
|
|
|
|
#### 2. PlatformAnalyzer 인터페이스
|
|
- 플랫폼별 특화 로직 구현을 위한 인터페이스
|
|
- 새로운 플랫폼 추가 시 이 인터페이스를 구현하거나 HttpBasedPlatformAnalyzer 상속
|
|
|
|
#### 3. HttpBasedPlatformAnalyzer (추상 클래스)
|
|
- HTTP 요청 기반 플랫폼 분석기의 공통 로직
|
|
- oEmbed API 호출 및 응답 처리
|
|
- 각 플랫폼은 `parseResponse()` 메서드만 구현
|
|
|
|
#### 4. VideoAnalyzerService
|
|
- 일반 비디오 URL 분석 로직
|
|
- 보호 검사, 3D 검사, AVPlayer 재생 가능 여부 검사
|
|
|
|
#### 5. CommonConstants & Messages
|
|
- `CommonConstants`: 도메인, API URL, 정규식 패턴 등
|
|
- `Messages`: 모든 메시지 문자열 (국제화 준비)
|
|
|
|
## 🧪 테스트 예제
|
|
|
|
### 기본 테스트 구조
|
|
|
|
```java
|
|
import org.junit.Test;
|
|
import static org.junit.Assert.*;
|
|
|
|
public class VideoAnalyzerTest {
|
|
|
|
@Test
|
|
public void testNaverTvUrl() {
|
|
VideoAnalyzer analyzer = new VideoAnalyzer();
|
|
VideoAnalysisResult result = analyzer.analyzeUrl("https://tv.naver.com/v/84373511");
|
|
|
|
assertNotNull(result);
|
|
assertNotNull(result.isSuccess());
|
|
assertNotNull(result.getReason());
|
|
}
|
|
|
|
@Test
|
|
public void testDrmProtectedUrl() {
|
|
VideoAnalyzer analyzer = new VideoAnalyzer();
|
|
String drmUrl = "https://example.com/video.m3u8?drm=widevine";
|
|
VideoAnalysisResult result = analyzer.analyzeUrl(drmUrl);
|
|
|
|
assertFalse(result.isSuccess());
|
|
assertTrue(result.getReason().contains("DRM"));
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🌟 새로운 플랫폼 추가하기
|
|
|
|
### 방법 1: HttpBasedPlatformAnalyzer 상속 (권장 - oEmbed 지원 플랫폼)
|
|
|
|
```java
|
|
public class InstagramPlatformAnalyzer extends HttpBasedPlatformAnalyzer {
|
|
|
|
private static final String PLATFORM_NAME = "Instagram";
|
|
private static final String PLATFORM_DOMAIN = "instagram.com";
|
|
private static final String API_ENDPOINT = "https://api.instagram.com/oembed";
|
|
|
|
private final ObjectMapper objectMapper;
|
|
|
|
public InstagramPlatformAnalyzer() {
|
|
this.objectMapper = new ObjectMapper();
|
|
}
|
|
|
|
@Override
|
|
protected String getApiEndpoint() {
|
|
return API_ENDPOINT;
|
|
}
|
|
|
|
@Override
|
|
protected String getPlatformDomain() {
|
|
return PLATFORM_DOMAIN;
|
|
}
|
|
|
|
@Override
|
|
public String getPlatformName() {
|
|
return PLATFORM_NAME;
|
|
}
|
|
|
|
@Override
|
|
public boolean canHandle(String url) {
|
|
if (url == null) return false;
|
|
return url.toLowerCase().contains(PLATFORM_DOMAIN);
|
|
}
|
|
|
|
@Override
|
|
protected VideoAnalysisResult parseResponse(String response, String originalUrl) throws IOException {
|
|
try {
|
|
JsonNode rootNode = objectMapper.readTree(response);
|
|
|
|
// 필수 필드 추출
|
|
String type = getStringValue(rootNode, "type");
|
|
String title = getStringValue(rootNode, "title");
|
|
|
|
if (type == null || title == null) {
|
|
return VideoAnalysisResult.failure("Instagram oEmbed 응답이 유효하지 않습니다");
|
|
}
|
|
|
|
logger.debug("Instagram 검증 성공: {}", title);
|
|
return VideoAnalysisResult.success();
|
|
|
|
} catch (Exception e) {
|
|
throw new IOException("Instagram 응답 파싱 실패: " + e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 방법 2: PlatformAnalyzer 직접 구현 (HTML 파싱이 필요한 경우)
|
|
|
|
```java
|
|
public class CustomPlatformAnalyzer implements PlatformAnalyzer {
|
|
|
|
@Override
|
|
public String getPlatformName() {
|
|
return "CustomPlatform";
|
|
}
|
|
|
|
@Override
|
|
public boolean canHandle(String url) {
|
|
return url != null && url.contains("custom.com");
|
|
}
|
|
|
|
@Override
|
|
public VideoAnalysisResult analyze(String url) {
|
|
try {
|
|
// 커스텀 분석 로직 (HTML 파싱 등)
|
|
String htmlContent = fetchHtmlContent(url);
|
|
String videoUrl = extractVideoUrl(htmlContent);
|
|
|
|
if (videoUrl != null) {
|
|
return VideoAnalysisResult.success();
|
|
} else {
|
|
return VideoAnalysisResult.failure("비디오 URL을 찾을 수 없습니다");
|
|
}
|
|
} catch (Exception e) {
|
|
return VideoAnalysisResult.failure("분석 실패: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
private String fetchHtmlContent(String url) throws IOException {
|
|
// HTTP 요청 구현
|
|
}
|
|
|
|
private String extractVideoUrl(String html) {
|
|
// HTML 파싱 구현
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. Factory에 등록
|
|
|
|
```java
|
|
public class PlatformAnalyzerFactory {
|
|
public PlatformAnalyzerFactory() {
|
|
this.analyzers = new ArrayList<>();
|
|
|
|
// HTTP 기반 플랫폼 분석기들을 등록
|
|
analyzers.add(new NaverTvPlatformAnalyzer());
|
|
analyzers.add(new KakaoTvPlatformAnalyzer());
|
|
analyzers.add(new YouTubePlatformAnalyzer());
|
|
analyzers.add(new VimeoPlatformAnalyzer());
|
|
analyzers.add(new TikTokPlatformAnalyzer());
|
|
analyzers.add(new TwitterPlatformAnalyzer());
|
|
analyzers.add(new WeiboPlatformAnalyzer());
|
|
|
|
// 새로운 분석기 추가
|
|
analyzers.add(new InstagramPlatformAnalyzer());
|
|
|
|
// 직접 URL 분석기는 가장 마지막에 등록 (fallback)
|
|
analyzers.add(new DirectUrlPlatformAnalyzer());
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. 테스트 작성
|
|
|
|
```java
|
|
@Test
|
|
public void testInstagramUrl() {
|
|
VideoAnalyzer analyzer = new VideoAnalyzer();
|
|
VideoAnalysisResult result = analyzer.analyzeUrl("https://www.instagram.com/p/ABC123/");
|
|
|
|
assertNotNull("결과가 null이 아니어야 합니다", result);
|
|
assertTrue("Instagram URL은 재생 가능해야 합니다", result.isSuccess());
|
|
|
|
System.out.println("Instagram: " + result);
|
|
}
|
|
```
|
|
|
|
### 5. 실제 예제: 웨이보 플랫폼
|
|
|
|
웨이보는 oEmbed를 지원하지 않아 HTML 파싱 방식으로 구현되었습니다.
|
|
자세한 구현은 `WeiboPlatformAnalyzer.java`를 참고하세요.
|
|
|
|
주요 특징:
|
|
- HTML에서 `og:video`, `og:title`, `og:image` 메타태그 추출
|
|
- `$render_data` 스크립트에서 JSON 데이터 파싱
|
|
- 여러 URL 패턴 지원 (tv/show, video/show, m.weibo.cn)
|
|
|
|
---
|
|
|
|
다시 한번 기여해주셔서 감사드립니다! 🎉
|