6P by GN⁺ | ★ favorite | 댓글 1개
  • YouTube 파일 URL은 /youtubei/v1/player API로 얻을 수 있지만, 그대로 내려받으면 비공식 다운로드 제한 때문에 속도가 극단적으로 느려짐
  • 2021년 중반 이후 URL에 붙는 n 쿼리 파라미터base.js의 JavaScript 알고리듬으로 변환해야 하며, 실패하면 YouTube가 조용히 속도를 제한함
  • n을 올바르게 처리해도 다운로드 시간은 영상 길이와 크기에 맞춰 조절되며, 예시에서는 1.5GB 영상이 약 4.0MB/s로 내려받아짐
  • HTTP Range 헤더로 파일을 10MB 조각으로 나눠 새 연결에서 받으면 제한이 걸리기 전에 각 조각을 빠르게 가져올 수 있음
  • 최종 파일은 별도 제공되는 비디오·오디오 스트림ffmpeg로 합쳐야 하며, yt-dlp, VLC media player, NewPipe, node-ytdl-core도 유사한 기법을 사용함

YouTube 파일 URL을 얻는 흐름

  • 실제 미디어 파일 URL은 /youtubei/v1/player 엔드포인트 호출로 가져올 수 있음
  • 이 API는 영상 제목, 설명, 썸네일, 포맷 정보를 반환하며, 포맷 목록에서 원하는 품질의 파일 URL을 고를 수 있음
    • 예시 영상 ID는 aqz-KE-bpKQ
    • 요청 본문에는 videoId, context.client.clientName, context.client.clientVersion 같은 값이 들어감
    • context 객체의 다른 값들은 API가 검증하는 전제 조건이며, 웹 브라우저 요청을 관찰해 허용 값을 찾음
  • API에서 받은 adaptiveFormats[0].url을 그대로 쓰면 다운로드가 사실상 막힌 수준으로 느려짐
    • 예시에서는 1.5GB 파일이 66.7kB/s 수준으로 표시됨
    • 속도는 대체로 40~70kB/s로 제한됨
    • 10분 영상을 모두 받는 데 약 6시간 30분이 걸릴 수 있음

n 파라미터가 만드는 첫 번째 제한

  • 2021년 중반 이후 YouTube는 대부분의 파일 URL에 n 쿼리 파라미터를 포함함
  • 이 값은 웹 페이지와 함께 배포되는 base.js 안의 JavaScript 알고리듬으로 변환해야 함
  • YouTube는 n 값을 공식 클라이언트 여부를 가르는 챌린지처럼 사용함
    • n이 없거나 올바르게 변환되지 않으면 다운로드 속도 제한이 조용히 적용됨
  • 변환 알고리듬은 난독화되어 있고 자주 바뀌기 때문에, 매번 내용을 역공학하는 방식은 실용적이지 않음
  • 예시 구현은 현재 플레이어 버전의 base.js를 내려받아 n 변환 코드를 추출한 뒤, 원래 n 값을 넣어 실행함
    • YouTube embed 페이지에서 base.js URL을 찾음
    • 정규식으로 챌린지 함수 이름과 함수 본문을 추출함
    • Node.js의 vm.runInNewContext로 변환 함수를 실행함
    • 변환된 값으로 URL의 n 파라미터를 교체함

n 변환 뒤에도 남는 속도 제한

  • n 파라미터를 올바르게 변환하면 초기의 극단적인 제한은 사라지지만, YouTube는 여전히 가변 다운로드 제한을 적용함
  • 제한 정도는 영상 크기와 길이에 따라 달라지며, 다운로드 시간이 영상 길이의 약 절반 정도가 되도록 맞춰짐
  • 미디어 파일을 항상 가능한 한 빠르게 제공하면 스트리밍 서비스 입장에서는 큰 대역폭 낭비가 될 수 있음
  • 예시 다운로드에서는 1.5GB 파일이 약 4.0MB/s로 내려받아짐

HTTP Range로 작은 조각을 빠르게 받기

  • 우회 방식의 핵심은 HTTP Range 헤더로 파일을 여러 작은 구간으로 나눠 다운로드하는 것임
  • Range 헤더는 각 요청에서 받을 파일 구간을 지정함
    • 예: Range: bytes=2000-3000
  • 예시 코드는 미디어 파일을 10MB 세그먼트로 나눠 처리함
    • 기존 출력 파일을 삭제함
    • 현재까지 받은 바이트 수를 기준으로 다음 10MB 구간을 계산함
    • 각 요청에 Range 헤더를 넣고 responseType: 'stream'으로 받음
    • 받은 데이터를 파일 뒤에 이어 씀
    • 진행률, 전체 크기, 세그먼트별 속도를 출력함
  • 이 방식은 제한 규칙이 적용되기까지 시간이 걸리고, 작은 세그먼트는 새 연결에서 매우 빠르게 받아질 수 있기 때문에 동작함
  • 테스트 출력에서는 1464.99MB 파일에서 다음 속도가 나타남
    • 0.68% 지점: 46.73MB/s
    • 1.37% 지점: 60.98MB/s
    • 2.05% 지점: 71.94MB/s
    • 6.14% 지점: 104.17MB/s
  • 일부 다운로드는 1Gb/s 연결을 거의 모두 사용할 정도였고, 평균 속도는 보통 50~70MB/s, 즉 400~560Mb/s 범위였음

비디오·오디오 병합과 기존 구현

  • YouTube는 비디오와 오디오 채널을 별도 파일로 배포함
  • 이 구조에서는 HD 또는 UHD 영상이 같은 오디오 파일을 재사용할 수 있어 저장 공간을 아낄 수 있음
  • 일부 영상은 언어별로 다른 오디오 채널도 제공함
  • 최종 단계에서는 ffmpeg로 비디오 파일과 오디오 파일을 하나로 합침
    • -c copy로 재인코딩 없이 스트림을 복사함
    • -map 0:v:0로 첫 번째 입력의 비디오 스트림을 선택함
    • -map 1:a:0로 두 번째 입력의 오디오 스트림을 선택함
    • 병합 후 임시 비디오·오디오 파일을 삭제함
  • 전체 예제 코드는 youtube-download.js로 제공됨
  • 여러 프로젝트가 YouTube 제한을 우회하기 위해 비슷한 기법을 사용함

댓글과 토론

Hacker News 의견들
  • yt-dlp 저장소 논의에서 본 바로는, 이 제한은 HTTP Range 헤더가 아니라 range=xxx 쿼리 매개변수를 붙이는 것만으로도 우회 가능했음
    범위를 전체 파일로 잡아도 다시 최고 속도가 나왔고, 기억이 맞다면 YouTube는 이미 이 제한을 풀었음
    참고: https://github.com/yt-dlp/yt-dlp/issues/6400

  • YouTube는 안 해봤지만, 더 수상한 스트리밍 사이트의 영상은 웹 개발자 도구로 받아본 적이 있음
    대부분 개발자 도구를 열면 건너뛸 수 없는 debugger 문을 만들고 CPU를 많이 쓰는 코드, 아마 무한 루프나 암호화폐 채굴기 같은 것을 실행해 영상을 멈추는 식의 보호를 씀
    더 중요한 건 이 코드가 네트워크 요청 정보도 지워서 지금까지 보낸 트래픽 분석을 어렵게 만든다는 점이고, Firefox의 “로그 보존”은 정말 로그를 보존해야 함
    완벽한 방어는 아니어서 결국 못 받은 영상은 없었지만, 이 동작 원리를 더 깊게 설명한 자료를 보고 싶음

    • 얼마 전 정확히 이런 방식을 피한 글이 올라왔고, 해법이 단순하면서도 효과적이었음: 브라우저를 다시 빌드하면서 debugger 키워드 이름을 바꿔버림
      웃음이 나올 정도였음
      https://news.ycombinator.com/item?id=36961445
    • 그런 안티 디버깅 기법을 우회하려면 Anti-Anti-Debug [0]를 써볼 만함
      비슷한 이유로 예전에 몇 시간 만에 만든 간단한 확장임
      0: https://chrome.google.com/webstore/detail/anti-anti-debug/mn...
    • 개발자 도구가 열렸는지 알 수 있다는 것 자체가 브라우저 쪽의 큰 결함처럼 느껴짐
      개발자 도구가 열렸는지 여부는 웹페이지가 절대 알아낼 수 없어야 하고, 제대로 구현할 수 있을 것 같음
    • Firefox에서 가끔 통하는 방법은 영상에서 shift+우클릭This FrameOpen Frame in New Tab을 누르는 것임
      새 탭에서는 개발자 도구가 동작함
    • 브라우저 개발자 도구를 감지하려는 페이지라면, 트래픽 분석에는 Wireshark를 먼저 써보는 게 떠오름
  • 최종 단계에서는 화면을 계속 보려면 WorldCoin으로 결제해야 하고, 그 거래 불가능한 WorldCoin은 광고를 봐야만 벌 수 있게 될 것 같음
    화면에 내장된 작은 Orb가 이를 감시하고, 이게 정말 기본소득을 위한 거라고 믿었던 건 아니겠지
    기본소득 문제는 은행 계좌와 고객확인(KYC)으로 오래전에 해결했음

    • 눈이랑은 아무 관련 없나?
  • 요즘 yt-dlp 속도 제한 문제를 겪는 사람이 있는지 궁금함
    항상 mpv로 YouTube를 보는데 내부적으로 yt-dlp를 쓰고, 지난주부터 상태가 아주 나빠졌음
    처음에는 500kB/s로 제한해둔 만큼 빠르게 시작하지만, 조금 지나면 3초 다운로드에 1초 재생분만 받아져서 재생 전에 한참 대기열에 넣어둬야 함
    git 버전의 yt-dlp를 쓰고 있는데 관련 이슈는 못 봤음

    • mpv는 yt-dlp로 영상 URL만 얻고 그 URL을 ffmpeg에 넘김
      ffmpeg는 Range 헤더 관련 우회책을 구현하지 않아서 속도 제한에 걸림
      yt-dlp가 직접 다운로드하게 하고 이를 mpv에 파이프로 넘겨 표준 입력에서 재생하게 할 수는 있지만, 아직 다운로드되지 않은 구간으로 탐색이 깨짐
      mpv 이슈 트래커에 이 문제 관련 이슈가 많음
  • YouTube는 이 과정에서 작은 부분을 계속 바꿈
    예전에 YouTube 영상용 내부 편집 도구를 만들었는데 MP4 파일이 필요했고, 한 달쯤마다 YouTube 변경 때문에 편집기가 깨져서 디버거로 무엇이 바뀌었는지 확인하고 맞춰야 했음

  • 옆길이지만, YouTube에서 보면 영상이 아주 조금 더 좋아 보이는 게 착각인지 궁금함
    즐겨보는 영상을 내려받아 VLC나 AppleTV의 Infuse로 보는데, YouTube 앱의 “nerd stats”로 같은 영상/오디오 스트림을 보고 있음을 확인할 수 있음
    그런데 YouTube가 블록형 압축 아티팩트를 더 부드럽게 보이게 하는 아주 미묘한 필터를 거는 것 같음
    가장자리를 강조하는 건 아니고, 가장자리가 없는 색 변화 영역을 찾아 블록형 아티팩트를 덜 눈에 띄게 만드는 느낌임
    착각일 수도 있지만 YouTube에서는 화면이 더 생생하고 단단해 보이고, 내려받은 영상은 배경이나 그림자에서 아주 미묘하지만 눈에 띄는 아티팩트와 잔떨림이 보여 1440p 영상도 최종 화질이 덜 좋아 보임
    오디오도 차이가 확실해서 YouTube는 대체로 음량이 균일한데, 내려받은 영상은 볼륨을 올려야 해서 불편함
    VLC나 Infuse도 YouTube처럼 영상을 더 보기 좋게 만드는 처리를 해줬으면 좋겠고, 색상이나 선명도 필터라기보다는 채널 간 경험을 일관되게 만드는 오디오 레벨링 같은 처리를 하는 듯함

    • 오디오는 답할 수 있음
      YouTube와 Spotify 같은 대부분의 스트리밍 사이트는 ReplayGain이라는 것을 씀
      영상이나 노래의 평균 음량을 계산한 태그이고, 업로드 시점에 계산됨
      공식 YouTube 클라이언트는 재생 시 그 태그를 사용해 볼륨을 조정하지만, 내려받을 때 태그가 빠지거나 MKV가 ReplayGain 태그를 기본 지원하지 않을 수도 있음
    • 플레이어가 쓰는 스케일링 필터와 색차 스케일링 방식이 선명도에 영향을 줌
      원본 해상도 스트림을 전체화면으로 재생하면 흑백 가장자리에서는 차이가 사라져야 함
      운영체제에 따라 두 전체화면 앱 사이를 빠르게 전환해 차이를 테스트할 수 있고, ISO 29170-2는 5Hz를 권장함
      색 변화는 영상 색 공간이나 모니터 프로파일 처리 실패에서 올 수 있으며, 이 경우 스크린샷이 실제 앱 화면과 다르게 보일 수도 있음
      잔떨림은 프레임 드롭일 수 있고, 색 있는 물체 가장자리의 픽셀화가 보인다면 최근접 색차 업스케일링일 가능성이 있음
    • YouTube 영상 하나에는 여러 영상·오디오·통합 스트림이 있음
      브라우저가 고르는 스트림과 youtube-dl 또는 포크가 기본으로 고르는 스트림이 다를 수 있음
      예전에는 한동안 최상 통합 스트림을 기본으로 골랐지만, 분리된 최상 오디오와 영상 스트림이 더 품질이 높음
    • VLC 같은 플레이어는 더 잘할 수 있고, GLSL로 원하는 보정을 직접 만들 수도 있음
      특히 anime4k 셰이더 팩을 좋아하는데, 기계학습 기반이지만 mpv에서 실시간으로 돌고 VLC에서도 될 것 같음
      이름처럼 애니메이션에 맞춰졌지만 잡음 제거와 흐림 제거가 괜찮아 YouTube 콘텐츠를 보기 좋게 만들 때가 많고, 복원 단계는 압축 아티팩트를 꽤 잘 처리함
      다만 애니메이션에 너무 맞춰져 있어 항상 잘 작동하지는 않고 오히려 나빠질 수도 있음
      https://github.com/bloc97/Anime4K/releases
    • 브라우저의 영상 파이프라인이 VLC가 쓰는 것과 다를 수 있음
      로컬 파일을 가리키는 video 요소가 들어간 간단한 HTML 문서를 만들어 비교해볼 수 있음
  • YT가 다운로드러를 상대로 또 반쪽짜리 조치를 배포할 때마다 놀람
    GOOG는 Widevine도 갖고 있는데, 왜 안 쓰는지 궁금함

    • Widevine 소프트웨어 버전은 아주 짧은 시간 안에 완전히 깨져서 원클릭 다운로드 애드온으로도 우회될 것임
      사용자에게 달라지는 건 없고 YouTube는 Widevine 운영 부담만 지게 됨
      하드웨어 기반 버전을 쓰면 지원되지 않는 기기에서 문제가 많이 생길 수 있음
    • YouTube는 콘텐츠를 불법 복제하거나 서드파티 클라이언트를 쓰는 것 자체에는 크게 신경 쓰지 않는 것 같음
      신경 쓰는 건 대역폭 낭비
      광고 기반 영상 스트리밍 사이트에서는 보통 대역폭 비용이 수익보다 비싼데, Google은 ISP에 무료 피어링을 압박할 수 있을 만큼 저렴한 대역폭을 확보해서 겨우 성립함
      이런 속도 제한은 모든 콘텐츠를 긁어가는 사람이 아니라 실제 사용자에게 대역폭 대부분을 남기려는 조치임
    • Widevine을 쓰지 않는 이유는 복호화 단계가 추가되어 느리고, 소프트웨어 영상 디코딩을 강제해 느리며, 웹브라우저는 효과가 약한 Widevine 최약 형태만 지원하기 때문임
      목표 달성에도 별로 효과적이지 않으면서 상당수 사용자를 플랫폼 밖으로 밀어낼 가능성이 큼
    • 주된 이유는 CDN 캐시 효율을 조금 떨어뜨려 비용이 들고, 추가 키 관리 시스템을 운영해야 하기 때문임
      YouTube 규모에서는 이런 시스템을 최대한 줄이고 싶어 함
      또한 Widevine Level 3를 아주 큰 공격 대상으로 만들어버림
      결국 재무 방정식이고, 광고 차단으로 잃는 돈이 아직 Widevine 스위치를 당길 만큼은 아니지만 더 약한 조치를 취할 정도는 되었고 음반사 압박도 있을 테니 몇 년 안에 더 넓게 배포될 가능성이 있음
      예측하자면 처음에는 Content ID에 잡힌 레이블 음악이나 스튜디오 클립이 들어간 영상부터 시작하고, 다른 제작자에게는 선택 태그를 제공할 수 있음
      그런 영상들이 수익화에 더 유용하고 CDN 이점을 한꺼번에 잃지도 않음
    • Google은 서드파티 클라이언트는 억제하되 사람들이 아카이브하는 것은 허용하고 싶을 가능성이 큼
      조용히 이런 반쪽짜리 조치를 취하는 게 그 목표를 달성하는 완벽하고도 유일한 해법임
  • YouTube가 영상을 어떻게 배포하는지 항상 궁금했음
    인터넷이 엉망일 때도 잘 됐고, 남미에서는 모든 플랫폼이 잘 돌아가는 것도 아닌데 YouTube는 가장 매끄러운 영상 플랫폼임
    가장 가까운 건 Netflix지만 그래도 많이 뒤처짐

    • 집 가까운 ISP 네트워크 안에 캐시 서버를 배치해둠
      ISP도 이득이 있으니 허용함
      ISP의 병목은 자체 네트워크에서 더 넓은 인터넷 백본으로 나가는 연결이고, 큰 CDN의 캐시 서버가 그 병목에서 큰 부하를 덜어줌
      Netflix의 비슷한 구성 문서: https://openconnect.netflix.com/
  • YouTube에서 영상을 직접 내려받아본 적이 있나?
    youtube-dl, yt-dlp, 그런 웹사이트에 의존하지 않고 수동으로 해보면 생각보다 훨씬 복잡함

    • 아주 오래전에 그런 일을 하는 Perl 스크립트를 작업한 적이 있음: https://www.perlmonks.org/?node_id=636777
      물론 이런 스크립트의 문제는 YouTube가 영상 다운로드를 막으려고 바꾸는 부분을 계속 뒤쫓아야 한다는 것임
    • 직접 사용자 스크립트를 주입해 처리함
      WEI를 보면 오래 못 갈 수도 있는 내 USER AGENT를 이용하는 방식임
      서명, n 디코딩, 속도 제한 함수를 다시 구현하려고 애쓰지 않고 player.jsmatch(/(?:player\/([a-zA-Z0-9_-]+)\/)?(?:html5player|(?:www|player(?:_ias)?))[-\.]([^/]+?)(?:(?:\/html5player(?:-new)?)?|(?:\/[a-z]{2,3}_[A-Z]{2})?\/base)\.js/)로 찾은 다음, 그 안에서 관련 함수를 grep해서 직접 호출함
      YouTube 입장에서는 자기 DRM 함수가 나를 위해 .mp4 링크를 열어주는 것이니 100% 정상처럼 보인다고도 할 수 있음
    • “Download” 버튼을 누르고 Premium 비용을 내는 방식 말인가?
  • 기술적으로는 전부 흥미롭지만, 윤리적으로 “Google 엿 먹어라”만 생각하지 않는다면 첫 번째 최적화, 즉 실제 브라우저 검사를 통과해 일반 브라우저 속도를 얻는 선에서 멈추는 게 합리적으로 느껴짐
    그 정도면 광고 차단 브라우저 사용자보다 YouTube 자원을 더 낭비하는 건 아님
    아무 비용도 내지 않고 Gb/s 전체 속도를 쓰는 건 광고 차단 사용자 전체의 운을 시험하는 느낌임
    물론 결국 Google 엿 먹어라일 수도 있음

    • 기술적으로는 모두가 네트워크 연결 비용을 내고 있음
      YouTube를 최대 속도로 때리는 게 비윤리적이라고까지 하진 않겠지만, YouTube가 막는 조치를 취해도 비난하진 않음
      소셜미디어 이미지에 마우스를 올리면 원본 크기로 보여주는 브라우저 확장을 쓰는데 Instagram이 비정상 활동 경고와 계정 잠금 위협을 띄웠음
      확장이 뒤에서 스크래핑을 하는지 확인했지만 별문제 없어 보였고, 아마 Meta는 표준 클라이언트와 다른 요청 순서를 보고 데이터 스크래핑으로 판단하는 듯함
      조치와 대응 조치의 반복이고, YouTube도 자기 대응책을 구현해 스크래퍼가 다시 대응하게 만들겠지만, 정당한 소비가 정식 클라이언트에서 재생 속도의 2배보다 빠를 일은 없으니 언젠가는 그 정도로 다운로드를 제한할 수 있을 것임
      그래도 다운로드 자체는 제한되면 안 된다고 봄
      콘텐츠는 이미 법으로 보호되고 있고, 대부분은 보관, 분석, 리뷰 영상 제작처럼 합당한 이유로 영상을 내려받음
      YouTube 콘텐츠는 진공 속에서 만들어지는 것이 아니며, 공개된 뒤에는 새 영상이 만들어질 환경을 만들기 때문에 이 창작의 자유가 중요함
    • 이것이 얼마나 남용인지 잘 모르겠음
      결국 같은 양의 데이터를 더 짧은 시간에 받는 것뿐이라 대역폭을 더 많이 쓰지만 더 빨리 사라짐
      일반 브라우저 사용 사례는 영상을 끝까지 보지 않는 흔한 상황에 맞춰 조정된 듯함
      처음부터 전체를 보고 보관하려는 경우라면 Google의 대역폭을 더 먹는다고 보긴 어렵고, 다만 연결 수 때문에 오버헤드는 더 클 수 있음
    • 기업에는 윤리가 아니라 이해관계만 있음
      나도 비슷하게 행동하는 게 자연스러움
    • YouTube 자원과 Gb/s라고 하지만, 대부분의 경우 영상은 같은 ISP 네트워크 안에서 제공됨
      YouTube가 전 세계 거의 모든 ISP와 인터넷 교환점에 캐시를 두고 있기 때문이고, 지금까지 만들어진 가장 큰 CDN일지도 모름
      예를 들어 글 작성자의 YouTube URL은 캐나다 ISP Videotron을 가리킴
      https://bgp.he.net/dns/rr1---sn-8qu-t0aee.googlevideo.com
    • 기술적으로는 영상을 다운로드할 수 있어야 하고, 막히면 안 됨
      누군가 혐오 발언을 퍼뜨리거나 나와 가족을 모욕했다는 증거를 남기기 위해서라도 필요함
      화면을 캠코더로 찍을 수도 있겠지만 석기시대식 해법처럼 들림
      예를 들어 Mac의 브라우저에서 Netflix는 스크린샷을 찍을 수 없어서, 공정 이용에 해당하는 밈 제작조차 빼앗긴 상태임