프로젝트 아키텍처

FlowPick의 기술 아키텍처 상세 설명, 시스템 설계, 모듈 분할, 데이터 흐름 및 핵심 설계 결정 포함.

이 문서는 FlowPick의 내부 설계를 깊이 이해하고 싶은 개발자를 대상으로 하며, 시스템 아키텍처, 모듈 역할, 데이터 흐름 및 핵심 설계 결정을 다룹니다.


시스템 아키텍처 개요

FlowPick는 두 가지 주요 제품 형태로 구성됩니다: 브라우저 확장 프로그램온라인 도구 웹사이트. 두 제품은 핵심 다운로드 엔진을 공유하지만, 미디어 검출 및 네트워크 요청 처리 방식에는 차이가 있습니다.

┌─────────────────────────────────────────────────────────┐
│                      FlowPick                           │
│                                                         │
│  ┌──────────────────┐    ┌──────────────────────────┐   │
│  │  브라우저 확장     │    │   온라인 도구 웹사이트     │   │
│  │                  │    │                          │   │
│  │ · 네트워크 요청 모니터링 │    │ · M3U8 다운로더       │   │
│  │ · 미디어 자동 검출  │    │ · DASH 다운로더        │   │
│  │ · 팝업창 UI      │    │ · 문서 시스템           │   │
│  │ · 크로스 오리진 요청 능력│    │ · 홈페이지 표시         │   │
│  └────────┬─────────┘    └────────────┬─────────────┘   │
│           │                           │                 │
│           └───────────┬───────────────┘                 │
│                       │                                 │
│           ┌───────────▼───────────────┐                 │
│           │      핵심 다운로드 엔진      │                 │
│           │                           │                 │
│           │ · useStreamMerge.ts       │                 │
│           │ · useFFmpeg.ts            │                 │
│           │ · 세그먼트 다운로드 및 동시성 제어 │               │
│           │ · AES-128 복호화            │                 │
│           │ · 스트리밍 파일 쓰기          │                 │
│           │ · 형식 변환                 │                 │
│           └───────────────────────────┘                 │
└─────────────────────────────────────────────────────────┘

두 가지 제품 형태의 포지셔닝:

차원브라우저 확장온라인 도구 웹사이트
대상 사용자일상적인 고빈도 사용자일시적 사용자, 확장 프로그램 설치 불가능한 환경
핵심 장점자동 검출, 원클릭 다운로드설치 불필요, 크로스 플랫폼
기술적 제약Manifest V3 제한동일 출처 정책 제한
진입 방식도구모음 아이콘 클릭웹 URL 직접 접근
확장 프로그램과 온라인 도구의 상세 기능 차이 및 선택 권장 사항에 대해서는 온라인 도구 — 확장과의 비교를 참조하세요. 확장 프로그램 설치 단계에 대해서는 설치 가이드를 참조하세요.

모듈 상세 설명

핵심 다운로드 엔진

다운로드 엔진은 두 개의 composable로 구성되며, app/composables/에 위치합니다.

useStreamMerge.ts

스트리밍 미디어 세그먼트의 다운로드, 복호화, 병합 및 쓰기를 담당합니다. 이는 전체 시스템에서 가장 핵심적인 모듈입니다.

주요 역할:

기능구현 방식
세그먼트 동시 다운로드Worker Pool 모드, 공유 작업 카운터
재시도 메커니즘지수 백오프, 최대 3회
AES-128 복호화Web Crypto API
세그먼트 연결이진 직접 연결(TS) 또는 FFmpeg 리무싱(MP4)
파일 쓰기FSA → StreamSaver → Blob 3단계 폴백
진행률 추적슬라이딩 윈도우 속도 계산 + 남은 시간 추정
메모리 관리샘플링 예측 + 임계값 확인 + 전략 선택

내보내기 인터페이스:

export interface StreamMergeOptions {
  segments: ArrayBuffer[] | AsyncGenerator<ArrayBuffer>
  totalSegments: number
  filename: string
  outputFormat?: 'mp4' | 'ts'
  onProgress?: (progress: StreamMergeProgress) => void
  signal?: AbortSignal
}

export interface StreamMergeProgress {
  phase: 'downloading' | 'merging'
  percent: number
  downloadedBytes: number
  totalBytes: number
  speed: string
  eta: string
}
다운로드 엔진의 완전한 기술 구현(동시성 제어, 재시도 전략, 메모리 관리, 쓰기 전략 비교 포함)에 대해서는 다운로드 엔진 아키텍처를 참조하세요. 3단계 쓰기 전략의 폴백 논리에 대해서는 다운로드 엔진 아키텍처 — 전략 비교 요약을 참조하세요.

useFFmpeg.ts

FFmpeg WASM의 로딩, 수명 주기 관리 및 미디어 처리 명령 실행을 담당합니다.

주요 역할:

기능구현 방식
WASM 로딩요청 시 로딩, 멀티스레드/싱글스레드 자동 전환 지원
멀티스레드 감지SharedArrayBuffercrossOriginIsolated 확인
TS → MP4 리무싱ffmpeg -i input.ts -c copy output.mp4
오디오/비디오 병합각각 가상 FS에 쓰고 병합 명령 실행
FMP4 재구성DASH의 초기화 세그먼트 + 미디어 세그먼트 처리
진행률 콜백FFmpeg 출력의 time 정보 파싱

내보내기 인터페이스:

export const useFFmpeg = () => {
  return {
    ffmpeg: Ref<FFmpegType | null>
    loaded: Ref<boolean>
    loading: Ref<boolean>
    error: Ref<string | null>
    load: () => Promise<void>
    mergeToMP4: (options: MergeOptions) => Promise<ArrayBuffer>
    mergeAudioVideo: (options: MergeAudioVideoOptions) => Promise<ArrayBuffer>
    mergeFmp4: (options: MergeFmp4Options) => Promise<ArrayBuffer>
  }
}
FFmpeg WASM의 로딩 흐름, 멀티스레드 감지 및 성능 비교에 대해서는 형식 변환 — FFmpeg WASM 엔진을 참조하세요. SharedArrayBuffer의 구성 요구사항에 대해서는 브라우저 호환성 — 고급 API를 참조하세요.

페이지 모듈

M3U8 다운로더 (m3u8-downloader.vue)

HLS 스트리밍 프로토콜을 처리하는 다운로드 페이지입니다.

처리 흐름:

사용자 URL 입력
    ↓
fetch M3U8 내용
    ↓
m3u8-parser 파싱
    ↓
┌─ Master Playlist? ──→ 화질 목록 표시 → 사용자 선택
│
└─ Media Playlist? ──→ 세그먼트 목록 추출
    ↓
#EXT-X-KEY 확인(암호화 정보)
    ↓
키 파일 다운로드(있는 경우)
    ↓
동시 세그먼트 다운로드 + 복호화
    ↓
병합/리무싱
    ↓
디스크에 쓰기
**

**핵심 의존성**:
- `m3u8-parser`: M3U8 매니페스트 파싱
- `useStreamMerge`: 세그먼트 다운로드 및 병합
- `useFFmpeg`: 형식 변환

::note
HLS 프로토콜의 Master Playlist와 Media Playlist의 차이점에 대해서는 [비디오 스니핑 — HLS 스트림](/ko/docs/features/video-sniffing#hlsm3u8-流)을 참조하세요. 온라인 도구에서 M3U8 다운로더의 사용 방법에 대해서는 [온라인 도구](/ko/docs/advanced/online-tools)를 참조하세요.
::

#### DASH 다운로더 (`dash-downloader.vue`)

DASH 스트리밍 프로토콜을 처리하는 다운로드 페이지입니다.

**처리 흐름**:

사용자 URL 입력 ↓ fetch MPD 내용 ↓ mpd-parser 파싱 ↓ ContentProtection 확인(DRM) ↓ AdaptationSet 추출(비디오/오디오) ↓ 스트림 목록 표시 → 사용자 선택 ↓ 초기화 세그먼트 다운로드(있는 경우) ↓ 동시 미디어 세그먼트 다운로드 + 복호화 ↓ FMP4 재구성 / 오디오/비디오 병합 ↓ 디스크에 쓰기


**핵심 의존성**:
- `mpd-parser`: MPD 매니페스트 파싱
- `useStreamMerge`: 세그먼트 다운로드 및 병합
- `useFFmpeg`: FMP4 재구성 및 오디오/비디오 병합

::note
DASH 스트림의 검출 원리 및 ContentProtection 처리에 대해서는 [비디오 스니핑 — DASH 스트림](/ko/docs/features/video-sniffing#dashmpd-流)을 참조하세요. DRM 보호 콘텐츠의 제한 사항에 대해서는 [알려진 제한 — DRM 보호 콘텐츠](/ko/docs/troubleshooting/known-issues#drm-保护内容)를 참조하세요.
::

---

### 문서 시스템

Nuxt Content v3를 기반으로 구축되었으며, 문서는 Markdown 파일 형태로 `content/` 디렉토리에 저장됩니다.

**디렉토리 구조**:

content/zh-Hans/ ├── 1.docs/ # 문서 본체 │ ├── 1.getting-started/ # 빠른 시작 │ ├── 2.features/ # 기능 특성 │ ├── 3.advanced/ # 고급 가이드 │ ├── 5.troubleshooting/ # 문제 해결 │ └── 6.developer/ # 개발자 문서 ├── 4.changelog/ # 변경 로그 └── 6.legal/ # 법률 조항 **

네비게이션 시스템: 각 디렉토리 하위의 .navigation.yml이 해당 분류의 제목과 아이콘을 정의합니다. Nuxt Content가 모든 문서를 자동으로 수집하여 사이드바 네비게이션을 생성합니다.

문서 레이아웃: app/layouts/docs.vue가 통일된 문서 페이지 레이아웃을 제공하며, 상단 네비게이션, 사이드바 및 콘텐츠 영역을 포함합니다.

문서 작성 규칙(Frontmatter, 콘텐츠 형식, 다국어)에 대해서는 기여 가이드라인 — 문서 작성 가이드를 참조하세요.

데이터 흐름

완전한 다운로드 흐름

┌─────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│ 매니페스트 가져오기 │ → │ 매니페스트 파싱 │ → │ 세그먼트 다운로드 │ → │ 병합 쓰기 │
└─────────┘    └──────────┘    └──────────┘    └──────────┘
     │              │               │               │
     ▼              ▼               ▼               ▼
  fetch()      m3u8-parser    Worker Pool     useStreamMerge
                mpd-parser    AES-128 복호화    useFFmpeg
                              fetch() 동시      FSA/SS/Blob
**

**각 단계 상세 설명**:

| 단계 | 입력 | 처리 | 출력 | 가능한 실패 원인 |
|------|------|------|------|---------------|
| 매니페스트 가져오기 | M3U8/MPD URL | HTTP GET 요청 | 매니페스트 텍스트 | 네트워크 오류, URL 만료, 404 |
| 매니페스트 파싱 | 매니페스트 텍스트 | m3u8/mpd-parser 파싱 | 세그먼트 목록 + 메타데이터 | 비표준 형식, DRM 보호 |
| 세그먼트 다운로드 | 세그먼트 URL 목록 | Worker Pool 동시 다운로드 | ArrayBuffer 배열 | CORS, 속도 제한, token 만료 |
| 병합 쓰기 | ArrayBuffer 배열 | 연결/리무싱 + 쓰기 | 디스크 파일 | 메모리 부족, 쓰기 권한 |

::note
다운로드 엔진의 완전한 데이터 흐름(오류 분류 및 재시도 메커니즘 포함)에 대해서는 [다운로드 엔진 아키텍처 — 데이터 흐름 전경](/ko/docs/advanced/download-engine#数据流全景)을 참조하세요. 각 단계 실패 시 해결 방법에 대해서는 [일반적인 문제 해결](/ko/docs/troubleshooting/common-issues)를 참조하세요.
::

### 쓰기 전략 선택 흐름

쓰기 시작 │ ▼ File System Access API 사용 가능? │ ├── 예 → FSA 스트리밍 쓰기 사용(최적) │ · 16MB 버퍼 │ · 임의 크기 지원 │ └── 아니오 → StreamSaver 사용 가능? │ ├── 예 → StreamSaver 스트리밍 쓰기 사용 │ · Service Worker 프록시 │ · 대용량 파일 지원 │ └── 아니오 → 파일 크기 예측 │ ├── < 1.5GB → Blob 모드 │ · 전체 메모리에 로드 │ · 브라우저 다운로드 트리거 │ └── > 1.5GB → 다운로드 거부 · 브라우저 전환 안내


::note
3단계 쓰기 전략의 상세 비교(각 전략의 적용 시나리오 및 제한 사항 포함)에 대해서는 [다운로드 엔진 아키텍처 — 전략 비교 요약](/ko/docs/advanced/download-engine#策略对比总结)을 참조하세요. 각 브라우저의 FSA API 지원 현황에 대해서는 [브라우저 호환성 — 기능 지원 매트릭스](/ko/docs/advanced/browser-compatibility)를 참조하세요.
::

## 핵심 설계 결정

### FFmpeg WASM을 선택하고 서버 측 처리하지 않은 이유?

**결정**: 모든 미디어 처리를 브라우저 측에서 수행합니다.

**이유**:
- 개인 정보 보호: 사용자 파일이 서버에 업로드되지 않음
- 제로 서버 비용: 트랜스코딩 서버 클러스터 유지 불필요
- 즉시 사용 가능: 업로드 및 대기 시간 없음
- 오프라인 능력: 이론적으로 PWA 모드에서 오프라인 사용 가능

**대가**:
- 원본 FFmpeg보다 성능 낮음(약 10-20%)
- 첫 로딩 시 WASM 파일 다운로드 필요(약 8MB)
- 브라우저 메모리 제한 受限

::note
FFmpeg WASM과 원본 버전의 성능 비교 데이터에 대해서는 [알려진 제한 — FFmpeg WASM 성능](/ko/docs/troubleshooting/known-issues#ffmpeg-wasm-性能)을 참조하세요. 개인 정보 보호의 완전한 설명에 대해서는 [개인 정보 및 보안](/ko/docs/features/privacy-security)을 참조하세요.
::

### 3단계 쓰기 폴백 전략을 사용하는 이유?

**결정**: FSA → StreamSaver → Blob 우선순위 체인.

**이유**:
- FSA API가 최적의 솔루션이지만 Chrome/Edge만 지원
- StreamSaver 호환성이 더 넓지만 Service Worker에 의존
- Blob이 최후의 수단으로 모든 브라우저에서 다운로드 가능하도록 보장

**대가**:
- 3세트의 쓰기 로직 유지 필요
- 폴백 동작으로 인해 사용자 경험 불일치 가능

::note
3단계 전략의 상세 구현 및 폴백 트리거 조건에 대해서는 [다운로드 엔진 아키텍처 — 파일 쓰기 모듈](/ko/docs/advanced/download-engine#文件写入模块)을 참조하세요. 각 브라우저의 쓰기 능력 비교에 대해서는 [브라우저 호환성 — 기능 폴백 전략](/ko/docs/advanced/browser-compatibility#功能降级策略)를 참조하세요.
::

### 동시 다운로드에 Worker Pool을 사용하고 미리 분할하지 않은 이유?

**결정**: 공유 카운터 + 동적 작업 할당 사용.

**이유**:
- 세그먼트 크기가 고르지 않을 때 미리 분할하면 일부 Worker가 유휴 상태가 됨
- 공유 카운터는 모든 Worker가 작업 완료까지 지속적으로 작업하도록 보장
- 구현이 간단하며 복잡한 부하均衡 로직 불필요

::note
Worker Pool의 동시성 제어 구현 및 성능 분석에 대해서는 [다운로드 엔진 아키텍처 — 동시성 수와 성능의 관계](/ko/docs/advanced/download-engine#并发数与性能的关系)을 참조하세요. 동시성 수 설정 방법에 대해서는 [설정 참조](/ko/docs/getting-started/configuration)를 참조하세요.
::

### 확장 프로그램과 온라인 도구가 핵심 엔진을 공유하는 이유?

**결정**: `useStreamMerge`와 `useFFmpeg`를 독립 composable로 확장 API에 의존하지 않음.

**이유**:
- 코드 재사용, 두 세트의 다운로드 로직 유지 불필요
- 온라인 도구가 확장 기능의 데모 및 폴백 솔루션으로 활용 가능
- 테스트 용이: 핵심 로직을 일반 웹 페이지 환경에서 디버깅 가능

::note
확장 프로그램과 온라인 도구의 CORS 처리 차이에 대해서는 [알려진 제한 — CORS 크로스 오리GIN 제한](/ko/docs/troubleshooting/known-issues#cors-跨域限制)을 참조하세요. 두 가지 제품 형태의 기능 비교에 대해서는 [온라인 도구 — 확장과의 비교](/ko/docs/advanced/online-tools)를 참조하세요.
::

## 의존성 관계도

m3u8-downloader.vue ──────┐ ├──→ useStreamMerge.ts ──→ Web Crypto API dash-downloader.vue ──────┤ │ fetch API │ ├──→ useFFmpeg.ts ──→ @ffmpeg/ffmpeg 확장 팝업창 ──────────────┘ │ @ffmpeg/util ├──→ File System Access API ├──→ StreamSaver.js └──→ Blob API

문서 시스템 ──→ @nuxt/content ──→ Markdown 파일 └──→ @nuxt/ui ──→ Tailwind CSS **

의존성 관계 설명: