Files
url-analyzer/CONTRIBUTING.md
2025-11-28 15:58:57 +09:00

9.1 KiB

🤝 기여 가이드

Video URL Analyzer 프로젝트에 기여해주셔서 감사합니다!

🚀 시작하기

1. Repository Fork & Clone

git clone https://github.com/your-username/video-url-analyzer.git
cd video-url-analyzer

2. 개발 환경 설정

요구사항

  • Java: 17 이상
  • Gradle: 7.0 이상

의존성 설치

./gradlew build

🔧 빌드 및 테스트

빌드

./gradlew clean build

테스트 실행

./gradlew test

Fat JAR 생성 (의존성 포함)

./gradlew fatJar

테스트 커버리지 확인

./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: 모든 메시지 문자열 (국제화 준비)

🧪 테스트 예제

기본 테스트 구조

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 지원 플랫폼)

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 파싱이 필요한 경우)

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에 등록

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. 테스트 작성

@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)

다시 한번 기여해주셔서 감사드립니다! 🎉