M3U8 다운로드 실패 해결 방법

M3U8·HLS 감지, CORS, 만료된 URL, Referer, DRM, 세그먼트 문제로 다운로드가 실패하는 원인과 해결 방법을 안내합니다.

M3U8 다운로드가 실패하는 원인은 대개 셋 중 하나입니다. 플레이리스트가 감지되지 않거나, 온라인 도구가 크로스 오리진 제한에 걸리거나, 스트리밍이 원본 동영상 페이지에서만 얻을 수 있는 접근 정보를 요구하는 경우입니다. 이 글에서는 HLS 실제 다운로드 파이프라인을 따라 단계별로 원인을 분리해, 어디서 왜 실패하고 어떻게 고치는지 설명합니다.


HLS 다운로드 파이프라인 이해하기

HLS는 "URL 하나로 파일 하나를 받는" 단순한 일이 아닙니다. 파이프라인이고, 어느 한 단계라도 깨지면 결국 "다운로드 실패" 또는 "파일 손상"으로 나타납니다. 이 흐름을 먼저 파악해야 진단 방향이 잡힙니다:

① M3U8 감지       ② 플레이리스트 파싱   ③ 세그먼트 다운로드   ④ 복호화   ⑤ 병합/리무싱
   ↓                  ↓                     ↓                 ↓            ↓
 webRequest        m3u8-parser           Worker Pool        WebCrypto    FFmpeg WASM
 요청 가로채기       Master/Media 구분     동시에 .ts 수신    AES-128-CBC  TS → MP4
                                        재시도·백오프      (필요한 경우)  또는 직접 연결
단계실패 증상해당 섹션
① 감지팝업에 "미디어가 감지되지 않음"M3U8이 감지되지 않음
② 파싱플레이리스트는 받았지만 화질/세그먼트 목록이 비어 있음플레이리스트 파싱 이상
③ 다운로드진행이 멈춤, 403, 404, CORS세그먼트 다운로드 실패
④ 복호화복호화 오류 또는 병합 후 소리 없음/화면 깨짐암호화 스트림 복호화 실패
⑤ 병합파일은 생성됐지만 재생 불가, 소리·화면 불일치병합 후 재생 불가
HLS 프로토콜과 플레이리스트 구조(Master vs Media Playlist, EXT-X-KEY, 다중 오디오 트랙)에 대한 완전한 설명은 비디오 스니핑 — HLS(M3U8)스트림을 참고하세요. 실제 플레이리스트가 어떤 모양인지, "단순한 다운로더"가 왜 실패하는지는 HLS 딥에서 확인할 수 있습니다.

먼저 시도할 것

깊이 파기 전에, 대부분의 문제(90%)를 해결할 수 있는 이 순서를 먼저 실행하세요:

  1. 원본 동영상 페이지를 열고 몇 초간 재생합니다(많은 사이트는 지연 로딩이라 재생하지 않으면 M3U8을 요청하지 않습니다).
  2. 확장 설치 후 페이지를 새로고침하지 않았다면 한 번 새로고침하세요(확장의 webRequest 감지는 페이지 로딩 이후에만 동작합니다).
  3. 확장으로 다시 감지하고 원하는 화질을 선택합니다.
  4. MP4 출력 형식을 고른 뒤 다운로드를 다시 클릭합니다.

그래도 안 되면 아래 섹션을 따라 원인을 찾으세요.


M3U8이 감지되지 않음

증상: FlowPick 팝업에 "미디어 리소스가 감지되지 않음"이라고 표시되거나, 목록에 썸네일/커버만 보이고 .m3u8 항목이 없습니다.

흔한 원인

원인확인 방법해결
동영상이 아직 로딩되지 않음재생하지 않고 확장을 열었음3~5초 재생 후 확장 열기
확장 설치 후 페이지를 새로고침하지 않음확장 설치 전에 페이지가 이미 로딩됨페이지 새로고침 후 요청 재발생
MSE를 사용하고 네이티브 HLS가 아님개발자 도구에서 .m3u8 요청이 보이지 않음아래 "MSE 사이트" 참고
플레이리스트가 크로스 오리진 iframe 안에 있음Network 패널에는 보이지만 확장이 못 잡음iframe 원본 페이지를 직접 열고 다시 감지
광고 차단 확장 등과 충돌다른 네트워크 계열 확장을 잠시 비활성화하면 감지됨화이트리스트에 추가하거나 로딩 순서 조정
커스텀/프라이빗 프로토콜Network에서 ws://, blob:, 암호화 스트림으로 보임FlowPick 미지원, 알려진 제한 참고

개발자 도구로 확인

F12Network 패널 → 필터 상자에 m3u8 입력:

  • 요청이 보인다면: 사이트가 실제로 HLS를 쓰고 있으며, 문제는 확장 감지 쪽입니다(대개 페이지 미새로고침 또는 다른 확장의 차단).
  • 요청이 보이지 않으면: 사이트가 MSE(Media Source Extensions)를 사용해 세그먼트를 <video>에 직접 공급하고 있으며, .m3u8을 아예 보내지 않습니다. 이런 사이트는 FlowPick이 감지할 수 없고, 이는 브라우저 레벨의 제한입니다.

MSE 사이트는 어떻게?

Network에서 .m4s / .chunk 요청은 많지만 플레이리스트 파일이 보이지 않는다면, MSE + 커스텀 세그먼트 로직을 사용하는 것입니다(YouTube가 대표적). 두 가지 해결책:

  • .mpd(DASH) 진입점을 찾아 DASH 다운로더로 전환하고, DASH 소리 안 나옴 해결을 참고.
  • <video> 태그의 srcblob:으로 시작하면 MSE가 생성한 것이므로 직접 다운로드할 수 없습니다. 사이트가 네이티브 HLS/DASH 플레이리스트를 직접 내보낼 때까지 기다려야 합니다.
확장 감지 원리(webRequest.onBeforeRequest, Content-Type 식별)와 25+ 종류의 MIME 유형 전체 목록은 비디오 스니핑 — 감지 원리를 참고하세요. 감지되지 않을 때의 체계적인 진단 절차는 일반적인 문제 해결 — 미디어 검출 문제를 참고하세요.

플레이리스트 파싱 이상

증상: M3U8은 감지됐지만 화질 목록이 비어 있거나, 세그먼트 수가 비정상적으로 적거나(예: 1개뿐), 다운로드해 보면 몇 KB밖에 안 됩니다.

Master인가 Media인가

HLS 플레이리스트는 두 계층입니다. 팝업에서 Media Playlist(세그먼트 목록 그 자체)를 보고 있다면 화질 선택 옵션이 없을 수 있고, 반대로 Master Playlist URL만 잡았는데 파싱된 변형(variant)이 모두 비어 있다면 플레이리스트 내용이 불완전한 것입니다.

Master Playlist          ← 360p / 720p / 1080p 변형 목록
    └── v_720.m3u8       ← Media Playlist, 수백 개의 .ts 세그먼트
            └── seg-001.ts, seg-002.ts, ...

플레이리스트 내용 직접 확인

M3U8 URL을 복사해 curl로 내용을 확인해 보세요(URL은 본인 것으로 교체):

curl -sL "https://cdn.example.com/index.m3u8"

정상적인 Master Playlist에는 #EXT-X-STREAM-INF 행이 보여야 합니다:

#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720
v_720.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=8000000,RESOLUTION=1920x1080
v_1080.m3u8

정상적인 Media Playlist에는 #EXTINF + 세그먼트 URL이 보여야 합니다:

#EXTM3U
#EXT-X-TARGETDURATION:6
#EXT-X-VERSION:3
#EXTINF:6.0,
seg-001.ts
#EXTINF:6.0,
seg-002.ts
#EXTINF:4.2,
seg-003.ts
#EXT-X-ENDLIST

흔한 이상 증상

확인된 내용문제처리
HTML 페이지 전체(로그인 페이지/에러 페이지)URL이 핫링크 방지로 리다이렉트됨403과 핫링크 방지 참고
#EXTM3U 한 줄뿐플레이리스트가 잘렸거나 응답 불완전페이지 다시 열어 새 URL 확보
#EXT-X-KEY는 있는데 세그먼트 없음암호화 스트림 키 실패로 이후 출력 없음암호화 스트림 복호화 실패 참고
#EXT-X-ENDLIST가 있는데 세그먼트가 5개 미만라이브 방송이 막 시작됐거나 종료됨라이브는 종료 후 다시보기 다운로드
세그먼트 URL이 상대 경로정상, 파서가 기본 경로를 자동 완성처리 불필요
실제 HLS 플레이리스트는 튜토리얼 예제보다 훨씬 복잡합니다(다중 오디오 트랙, 자막, CODECS 필드, 불연속성 태그 등). 이런 부분이 "단순한 다운로더"가 실패하기 쉬운 지점입니다. 완전한 파싱 로직은 HLS 딥비디오 스니핑 — Master Playlist vs Media Playlist를 참고하세요.

세그먼트 다운로드 실패

증상: 진행률이 절반쯤에서 오류가 나거나 멈추고, 콘솔에 403/404/CORS 오류가 쏟아집니다.

403과 핫링크 방지

세그먼트나 플레이리스트 요청이 403 Forbidden을 반환하면, 거의 대부분 핫링크 방지 검증을 통과하지 못한 것입니다. 흔한 세 가지 유형:

유형증상FlowPick 처리
Referer 검증curl로는 받을 수 있는데 브라우저 확장이 가끔 403v1.1.1부터 확장이 원본 페이지 Referer 자동 주입
Cookie/로그인 상태비로그인 시 403, 로그인 후 정상원본 동영상 페이지에서 확장을 사용하면 Cookie 전달
단기 TokenURL에 ?token=xxx&expires=yyy가 있고 몇 분 후 만료아래 "만료된 링크" 참고

확장의 핫링크 방지 프록시(v1.1.1+)

v1.1.1부터 FlowPick은 핫링크 방지 프록시 미리보기와 다운로드를 내장합니다. 이미지 목록, 비디오 커버, 호버 미리보기, 이미지/오디오/문서/자막 다운로드가 모두 자동으로 프록시를 경유하며, 원본 페이지의 Referer와 Cookie를 함께 보내고 저장 전에 응답을 검사합니다. 핫링크 방지로 반환된 HTML 에러 페이지를 이미지나 오디오로 저장하는 일을 막기 위해서입니다.

이전 버전을 쓰고 있다면 v1.1.1+로 업그레이드한 뒤 Bilibili 등 Referer 검증이 있는 사이트의 다운로드 성공률이 크게 올라갑니다. 업그레이드 방법은 설치 가이드 — 확장 업데이트를 참고하세요.

온라인 도구가 자주 403이 나는 이유

온라인 도구는 flowpick.com 도메인에서 동작하므로, 브라우저가 대상 사이트의 Cookie와 원본 페이지 Referer를 함께 보내지 않습니다. 원본 서버가 핫링크 방지를 한다면 온라인 도구는 거의 실패합니다. 핫링크 방지가 있는 사이트는 확장을 사용하고, 원본 동영상 페이지에서 조작하세요.

curl로 403 재현

Referer 문제인지 확인하는 가장 빠른 방법:

# Referer 없이, 아마 403
curl -I "https://cdn.example.com/seg-001.ts"

# 원본 페이지 Referer를 붙이면 200이어야 함
curl -I -H "Referer: https://www.example.com/watch/123" "https://cdn.example.com/seg-001.ts"

두 번째가 200이면 Referer 검증이 확실합니다.

만료된 링크(동적 Token)

라이브 다시보기와 일부 플랫폼의 주문형(VOD) 콘텐츠는 단기 Token을 사용합니다:

https://cdn.example.com/seg-001.ts?token=ab12cd34&expires=1692300000

expires는 Unix 타임스탬프로, 이 시각이 지나면 403/404가 됩니다. 증상:

  • 다운로드가 잘 진행되다가 중간에 갑자기 전 세그먼트가 403.
  • 페이지를 다시 열면 또 받아지지만, 잠시 후 다시 끊김.

처리:

  • 플레이리스트를 감지하면 빠르게 다운로드를 시작하세요. 팝업에서 너무 오래 머뭇거리지 마세요.
  • 대용량 파일이 Token으로 잘렸다면 원본 페이지를 새로고침해 확장이 새 플레이리스트를 잡게 하고, 남은 부분을 계속 받으세요(FlowPick의 실패 재시도는 일시적인 변동을 처리하지만, Token 만료는 하드 실패라 새 플레이리스트가 필요합니다).
FlowPick의 다운로드 재시도는 지수 백오프 방식으로 일시적인 네트워크 변동은 커버하지만, Token 만료 같은 하드 실패는 우회할 수 없습니다. 재시도 메커니즘에 대한 자세한 내용은 다운로드 엔진 아키텍처 — 재시도 메커니즘을 참고하세요.

404 세그먼트 삭제됨

라이브 다시보기에서 흔합니다. 라이브 종료 후 플랫폼이 제한된 기간 동안만 다시보기 세그먼트를 보관하며, 기간이 지난 세그먼트는 그냥 404입니다.

  • 다른 화질로 시도해 보세요(화질마다 다른 세그먼트 파일일 수 있음).
  • 다시보기가 유효기간 내인지 확인하세요.

CORS 오류

콘솔에 has been blocked by CORS policy가 뜨면, 대부분 온라인 도구에서 발생합니다. 확장은 host_permissions가 있어서 동일 출처 정책(Same-Origin Policy)의 제한을 받지 않습니다.

도구CORS 증상처리
브라우저 확장CORS 미발생
온라인 도구플레이리스트/세그먼트 크로스 오리진 요청이 차단됨확장 사용; 또는 원본 서버가 Access-Control-Allow-Origin을 반환하는지 확인
CORS는 브라우저 보안 메커니즘이지 버그가 아닙니다. 온라인 도구와 확장의 기능 차이 및 선택 가이드는 온라인 도구 — 확장과의 차이점을 참고하세요.

다운로드 중간에 네트워크 끊김

일시적인 네트워크 변동은 재시도 메커니즘이 커버합니다. 계속 실패할 때:

  • 네트워크 안정성 확인(특히 프록시/VPN 환경, 일반적인 문제 해결 — 프록시/VPN 환경 참고).
  • 동시 스레드 수를 2~3으로 낮춰 동시 연결 수를 줄이세요(일부 CDN은 과도한 동시 연결을 거부합니다).
  • 방화벽이 스트리밍 CDN 도메인을 차단하고 있지 않은지 확인하세요.
동시성은 어떻게 설정하나요? 기본값 2는 보수적이고, 데스크톱 네트워크라면 46 권장, CDN 대역폭 제한이 심한 사이트는 23으로 낮추세요. 설정 방법은 설정 참조, 동시성과 성능의 관계는 다운로드 엔진 아키텍처 — 동시 다운로더를 참고하세요.

암호화 스트림 복호화 실패

증상: 플레이리스트에 #EXT-X-KEY가 있고 다운로드는 끝까지 진행되지만, 병합 후 소리가 없거나 화면이 깨지거나 재생이 안 되고, 콘솔에 복호화 오류가 표시됩니다.

먼저 AES-128인지 DRM인지 구분

FlowPick은 AES-128처럼 "맨몸(裸)" 암호화만 지원합니다. 아래 태그가 보이면 모두 받을 수 없습니다:

# AES-128 —— 지원
#EXT-X-KEY:METHOD=AES-128,URI="https://cdn.example.com/key.bin",IV=0x...

# SAMPLE-AES / FairPlay —— 미지원(DRM에 가까움)
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="skd://..."

# Widevine / PlayReady(DASH에서 흔함) —— 미지원
<ContentProtection schemeIdUri="..."/>

AES-128 복호화 실패의 흔한 원인

원인확인 방법처리
키 URL 403/404콘솔에서 키 가져오기 실패원본 페이지에서 확장 사용(Cookie/Referer 포함); 키에도 Token이 있을 수 있음
키에 로그인 상태 필요비로그인 시 키 403, 로그인 후 정상먼저 로그인 후 다운로드
IV 누락플레이리스트의 #EXT-X-KEYIV= 없음FlowPick이 규격대로 세그먼트 번호로 IV를 유도, 수동 처리 불필요
키가 16바이트 아님curl로 받아보니 길이가 다름원본 서버 문제로 FlowPick으로 해결 불가

curl로 키 검증

# 키를 받을 수 있는지 확인. Referer/Cookie를 붙이는 것 잊지 말 것
curl -sL -H "Referer: https://www.example.com/watch/123" \
     "https://cdn.example.com/key.bin" | wc -c
# 정상이면 16이 출력되어야 함

출력이 16이 아니면 키 자체에 문제가 있는 것이고, 16인데도 확장이 복호화에 실패하면 대개 확장이 요청 시 Cookie/Referer를 못 붙인 것입니다(v1.1.1+로 업그레이드하면 핫링크 방지 프록시가 자동으로 붙입니다).

DRM 콘텐츠는 어떻게?

Widevine, PlayReady, FairPlay, SAMPLE-AES 같은 DRM 보호 콘텐츠는 FlowPick이 명시적으로 거부합니다. 이는 버그가 아니라 설계입니다. DRM을 풀 수 있다고 주장하는 다운로더는 거짓말을 하거나 불법입니다. 법적·기술적 경계는 스트리밍 비디오 다운로드 합법성 가이드를 참고하세요.

DRM 감지 방식과 미지원 목록 전체는 알려진 제한 — DRM 보호 콘텐츠를, AES-128 복호화의 Web Crypto 구현은 비디오 스니핑 — 암호화 스트림(AES-128)을 참고하세요.

병합 후 재생 불가

증상: 파일은 받았고 크기도 정상인데, VLC/플레이어가 열리지 않거나, 화면만 있고 소리가 없거나, 소리와 화면이 어긋납니다.

먼저 VLC로 테스트

VLC는 호환성이 가장 좋은 플레이어라, 먼저 "플레이어 문제"를 배제하세요:

  • VLC는 재생되는데 시스템 플레이어가 안 되면 → 코덱/컨테이너 호환성 문제, 플레이어 변경.
  • VLC도 재생이 안 되면 → 파일 자체 문제.

흔한 원인

증상원인처리
파일이 몇 KB뿐플레이리스트를 받았지 동영상이 아님리소스를 다시 선택하고, .m3u8이 아니라 동영상을 선택했는지 확인
화면만 있고 소리 없음다중 오디오 트랙 플레이리스트에서 비디오 트랙만 받음아래 "다중 오디오 트랙" 참고
소리·화면 불일치HLS 세그먼트 PTS 불연속TS 출력 형식으로 전환하거나 FFmpeg로 트랜스코딩
화면 깨짐/손상일부 세그먼트 다운로드 실패로 병합 불완전다시 다운로드해 모든 세그먼트가 온전한지 확인
MP4는 안 열리는데 TS는 재생됨리무싱 시 stsd box 작성 오류아래 "TS vs MP4" 참고

다중 오디오 트랙 플레이리스트

실제 HLS 플레이리스트(Netflix, Disney+ 같은 곳)는 오디오와 비디오를 따로 두는 경우가 많습니다:

#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac-128",NAME="English",DEFAULT=YES,URI="audio/eng_128.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=3000000,...,AUDIO="aac-128"
v_720.m3u8

다운로더가 v_720.m3u8만 잡아 세그먼트를 연결한다면, 결과물은 소리 없는 동영상입니다. FlowPick은 오디오 트랙도 동시에 받아 병합하지만, 전제 조건은 비디오 스트림뿐 아니라 오디오를 포함한 변형을 선택하는 것입니다. 다중 오디오 트랙 플레이리스트의 완전한 처리는 HLS 딥 — 멀티 오디오 트랙: #EXT-X-MEDIA를 참고하세요.

TS vs MP4 출력 형식

MP4가 안 열리는 경우, 먼저 TS 출력 형식으로 전환해 보세요. 이유:

  • TS 세그먼트는 그대로 연결하는 방식이고, MPEG-TS는 codec 정보를 내장하고 있어 거의 틀리지 않습니다.
  • MP4 리무싱은 CODECS 필드 해석과 stsd box 작성을 정확히 해야 하는데, 비표준 codec 식별자가 있으면 실패하기 쉽습니다.

TS는 재생되는데 MP4가 안 되면 대개 리무싱 문제이므로, 우선 TS로 임시 처리하고 MP4가 필요하면 FFmpeg 명령줄로 직접 한 번 변환하세요:

ffmpeg -i output.ts -c copy output.mp4

-c copy는 재인코딩하지 않아 몇 초면 끝납니다.

TS/MP4 리무싱 원리와 FFmpeg WASM 구현은 포맷 변환을, 브라우저 내 병합 전체 흐름은 FlowPick이 브라우저에서 수백 개 동영상 세그먼트를 MP4로 병합하는 방법을 참고하세요.

대용량 파일 / 브라우저 멈춤

증상: 대용량 파일(1GB 초과) 다운로드 시 브라우저가 버벅이거나 크래시되고, 일정 비율까지 받다가 그냥 중단됩니다.

이는 HLS 자체의 문제가 아니라 쓰기 전략 문제입니다. FlowPick의 3단계 쓰기 전략:

전략적용 조건상한
File System Access APIChrome/Edge 86+하드 상한 없음
StreamSaver.jsService Worker 지원 브라우저하드 상한 없음
Blob 최후 수단그 외1.5GB 하드 제한

Blob 모드에서는 1.5GB 초과 시 바로 거부됩니다. 해결책:

  • Chrome 86+ 또는 Edge 86+를 사용하고 "저장 디렉토리 선택" 기능을 활성화하세요.
  • Firefox는 FSA를 지원하지 않으므로, 대용량 파일은 StreamSaver나 OPFS 임시 저장을 사용합니다(v1.1.1+ 최적화).
  • 그래도 안 되면 동시성을 1~2로 낮춰 메모리 사용량을 줄이세요.
3단계 쓰기 전략 비교와 폴백(fallback) 로직은 다운로드 엔진 아키텍처 — 전략 비교 요약을, 대용량 파일 진단은 일반적인 문제 해결 — 대용량 파일 다운로드 실패를 참고하세요. Firefox의 OPFS 임시 저장 동작은 설치 가이드 — Firefox를 참고하세요.

진단 도구 빠른 참조

진단 시 F12로 개발자 도구를 열고, 아래가 가장 자주 쓰는 체크포인트입니다:

체크패널조작
M3U8 요청 여부Network필터 상자에 m3u8 입력, 페이지 새로고침 후 동영상 재생
세그먼트 요청 상태 코드Network필터 상자에 .ts 또는 .m4s 입력, Status 열 확인
요청에 어떤 헤더가 실렸는지Network → 요청 선택 → HeadersRequest Headers의 Referer/Cookie 확인
복호화 오류Consoledecrypt 또는 AES 검색
병합 오류Consoleffmpeg 또는 wasm 검색

환경 진단 보고서 생성

복잡한 문제는 Console에서 아래 코드를 실행해 환경 정보를 생성하면 피드백에 유용합니다:

const report = {
  ua: navigator.userAgent,
  fsa: 'showDirectoryPicker' in window,
  sab: typeof SharedArrayBuffer !== 'undefined',
  coi: self.crossOriginIsolated,
  storage: await navigator.storage?.estimate().catch(() => null),
  ts: new Date().toISOString(),
}
console.log(JSON.stringify(report, null, 2))

보고서에는 브라우저 환경 정보만 포함되며, 브라우징 기록이나 개인 데이터는 일절 포함되지 않습니다.


정말로 다운로드할 수 없는 경우

FlowPick은 공개된 표준 HLS 플레이리스트를 대상으로 합니다. 다음 시나리오는 설계상 미지원이며 버그가 아닙니다:

  • DRM 보호 콘텐츠(Widevine / PlayReady / FairPlay / SAMPLE-AES)
  • 로그인 우회나 페이월 돌파가 필요한 콘텐츠
  • MSE 커스텀 세그먼트를 사용하고 네이티브 M3U8/MPD를 내보내지 않는 사이트
  • 프라이빗 프로토콜, WebSocket, WebRTC로 전송되는 미디어

이런 경우 올바른 동작은 조용히 손상된 파일을 만드는 것이 아니라 오류를 내는 것입니다. 이것이 FlowPick의 태도입니다. 법적·기술적 경계에 대해서는 스트리밍 비디오 다운로드 합법성 가이드를 참고하세요.


관련 문서