사이드프로젝트 slecs

영상 감지율을 60%에서 94%로 끌어올린 네트워크 후킹 도입

목차

문제 상황

이전 videoDetector는 페이지 로드 시점의 <video> 태그만 훑고 끝났음. 그러다 보니

  • SPA에서 라우팅 후 동적으로 붙는 영상은 놓침
  • 플레이어가 blob URL이나 MSE로 스트림을 주입하면 src가 비어있어서 못 잡음
  • API가 m3u8 매니페스트만 내려주고 DOM에는 아무것도 안 박히는 케이스도 있음

결국 "감지율 60% 언저리"라는 피드백이 누적됐고, 이번 커밋에서 한 번에 갈아엎기로 함.

접근 방식

크게 세 갈래로 감지 채널을 쪼갰음.

채널 감지 대상 트리거
DOM 스캔 정적 <video>, <source> 초기 로드
MutationObserver 동적 추가/속성 변경 childList + attributes
네트워크 후킹 XHR/fetch 응답의 영상 URL 요청 완료 시

DOM만 보던 시절에는 "있다/없다"가 명확했는데, 네트워크 후킹을 추가하니까 영상 자체가 DOM에 없어도 매니페스트 URL로 존재 여부를 추정할 수 있게 됨.

핵심 코드

fetch 후킹은 원본 보존이 관건이라 Proxy로 감쌌음.

const origFetch = window.fetch;
window.fetch = async (...args) => {
  const res = await origFetch(...args);
  const url = typeof args[0] === 'string' ? args[0] : args[0].url;
  if (/\.(m3u8|mpd|mp4|webm)(\?|$)/i.test(url)) {
    notifyDetected({ url, source: 'fetch' });
  }
  return res;
};

XHR도 비슷하게 open/send를 가로채서 responseURL을 검사함. 다만 응답 본문까지 파싱하면 비용이 너무 커서 URL 패턴 매칭선에서 끊었음.

빠졌던 함정들

  • 이중 후킹: 페이지 내 다른 확장 프로그램이 이미 fetch를 감쌌을 때, 또 감싸면 무한루프 비슷하게 됨. __videoDetectorPatched 플래그로 가드.
  • CSP 위반: inline script로 주입하던 초기 버전은 strict CSP 사이트에서 죽었음. content script 컨텍스트로 옮기고 메시지 패싱으로 처리.
  • MutationObserver 폭주: 광고 DOM이 초당 수백 번 갈리는 사이트에서 CPU 튐. attributeFilter: ['src']로 좁히고 디바운스 적용.

결과

테스트한 30개 사이트 기준 감지율이 60% → 94%로 올라감. 못 잡은 6%는 대부분 DRM 걸린 EME 스트림이라 어차피 URL을 줘도 못 받는 영역. 여기는 별도 안내 UI를 띄우는 쪽으로 정리하기로 함.

다음

  • 응답 본문 sniffing(매니페스트 안의 variant URL까지) 옵션화
  • WebRTC/MSE 트래커 분리
  • 후킹 충돌 시 fallback 로깅

끝.

댓글 0

첫 댓글 달아줘.