Search
Duplicate
moon
sun

[실전]파괴적_리버스엔지니어링_REA(2)youtube 다운로드실전

목차(클릭하세요)
💡
본래 브라우저에서 작동하는 방식으로 구동하려 하였으나, 여러 제약조건으로 로컬의 백엔드에서 작동하는 교육용 유튜브 다운로드 실행 프로그램 이 프로그램은 설치도 귀찮은 분을 위한 배포형 실행파일

[ 타겟 site]

[깃허브 배포]
youtubedown
roughkyo

1. 기존 유튜브 영상 다운로더의 한계

1-1. 주소표시줄에 ss를 넣거나 하는 다양한 방법이 존재했음

•
상당히 오랜기간 유용하게 사용해왔지만, 가끔은 다운로드가 막히는 상황이 발생함
•
기존 다운로더는 대부분 실패해도 원인과 해결 방법을 알려주지 않음
◦
YouTube가 바뀌면 다운로드 엔진(yt-dlp)을 업데이트하기 전까지 다운로드가 실패함

1-2. REA로 다운로드 기능 분석 및 구현

#작업상황: Claude Code(데스크톱 앱) + REA MCP / 모델: Opus 5.5 / 추론강도: 중간
[예시 프롬프트]
대상 서비스:https://ko.savefrom.net/229au/ rea방식으로 역설계해서 app이 아닌 web용으로 만들어보자. 먼저 로컬에서 test까지 진행해봐.
JavaScript
복사
•
대상 서비스 자리에 분석할 사이트나 파일을 넣어 사용하기
•
이후 추가 요청 순서
◦
480p와 원본 화질 추가, 다운로드 실패 상황 분석과 log 기록 기능 추가
◦
음악 다운로드 기능도 추가

1-3. 중점사항

•
URL 입력 → 영상 정보 확인 → 동영상·음원 선택 → 파일 저장 순서로 진행됨
•
동영상과 음원을 각각 저장해 형식, 파일명, 진행 표시, 실패 메시지 기록하기
•
특히, 실패하는 상황을 분석하여 log 기록을 남기는 기능을 추가함
◦
실패 원인과 해결 방법을 화면에 바로 표시함
◦
실패마다 로그 파일을 남겨 나중에 원인을 추적할 수 있음

2. REA분석 결과 및 클린룸 방식 재구성

2-1. 정적 분석 절차

•
REA로 런타임과 패키징 방식을 확인하고, 내부 문자열에서 다운로드 형식과 옵션을 파악함
•
분석 결과는 기능 명세(SPEC.md)로 정리함
# 유튜브 다운로더 웹판 — 기능 명세 ## 1. 출처 - 기존 유튜브 다운로드 프로그램과 웹 서비스 등을 복합적으로 정적 분석해 기능 명세를 만들었습니다. - 본래 웹서비스용으로 기획하였으나, 구현과정에서 exe실행파일용으로 변경되었습니다. ## 2. 기능 - 입력: YouTube 링크 1개 - 형식 5가지 | 모드 | format | 출력 파일명 | 후처리 | |---|---|---|---| | best (원본 화질) | `bv*+ba/b` | `제목 (원본 2160p).mp4` | mp4로 합치되 담을 수 없는 코덱이면 mkv | | 1080 | `bv*[height<=1080]+ba/b[height<=1080]/best` | `제목 (1080p).mp4` | mp4로 병합 | | 720 | `bv*[height<=720]+ba/b[height<=720]/best` | `제목 (720p).mp4` | mp4로 병합 | | 480 | `bv*[height<=480]+ba/b[height<=480]/wv*+ba/w` | `제목 (480p).mp4` | mp4로 병합 | | mp3 | `ba/b` | `제목.mp3` | FFmpegExtractAudio mp3 192kbps | - 공통 옵션: `noplaylist`, `windowsfilenames`, `ffmpeg_location`, `progress_hooks` - 중지: 사용자가 중지하면 progress hook이 다운로드를 중단하고 작업 폴더를 지움 - 진행 표시: 진행률 막대와 진행 로그. 경고는 `[경고] `, 에러는 `[에러] ` 접두어 - 결과: 성공, 중지, 실패 세 가지로 나눠 표시 ## 3. 구조 브라우저 작동 방식이 아닌, **컴퓨터의 로컬에서 백엔드로 작동되는 방식**입니다. - 서버: Python 표준 라이브러리 `ThreadingHTTPServer` + yt-dlp + ffmpeg. `127.0.0.1`에만 바인딩 - API | 메서드 | 경로 | 설명 | |---|---|---| | GET | `/api/info` | yt-dlp 버전, 업데이트 필요 여부, ffmpeg·JS 런타임 상태 | | POST | `/api/jobs` | `{url, mode: "best"\|"1080"\|"720"\|"480"\|"mp3"}` → `{id}` | | GET | `/api/jobs/{id}?since=n` | 상태, 진행률, n번째 이후 로그 | | POST | `/api/jobs/{id}/cancel` | 중지 요청 | | GET | `/api/jobs/{id}/file` | 완료된 파일 다운로드 (UTF-8 파일명) | | GET | `/api/jobs/{id}/log` | 실패 로그 다운로드 | ## 4. 안전 장치 - 오류를 무시하지 않음 (`ignoreerrors` 미사용): 실패를 성공처럼 처리하지 않고 정확한 오류를 보여줌 - 주소는 YouTube 도메인(`youtube.com`, `youtu.be`, `music.youtube.com`)만 허용 - Host 헤더 검사로 DNS rebinding 차단, POST는 JSON 요청만 허용 - 동시에 실행되는 작업은 최대 2개 - Node.js가 있으면 yt-dlp의 JS 런타임으로 사용 (`js_runtimes`), `yt-dlp-ejs` 포함 ## 5. 실패 분석과 로그 (`diagnose.py`) - 오류 메시지와 경고 로그를 규칙표로 분류: 비공개, 연령 제한, 봇 확인, 지역 제한, 저작권, 삭제, 라이브, 화질 없음, ffmpeg 없음, 변환 실패, 429, 403, 추출기 오류, 네트워크, 디스크 부족, 파일 잠김, yt-dlp 노후 - 설치된 yt-dlp와 실행 중인 yt-dlp 버전이 다르면 "서버 재시작 필요"로 진단 - 실패마다 `logs/<YYYYMMDD-HHMMSS>_<작업ID>.log` (진단, 환경, 진행 로그, Traceback)를 쓰고 `logs/failures.jsonl`에 한 줄 추가 - 화면에 원인과 해결 방법을 보여주고, 로그 파일을 내려받을 수 있음 - 사용자 중지는 실패로 기록하지 않음 ## 6. 화면 - 디자인은 NexaCore 템플릿(hirael.com)을 참고해 어두운 남색 배경과 그라데이션 강조로 만들었습니다. - 하단 표기는 `제작: yangphago`이며, "교육용 목적에 한함" 주의사항과 화질 선택 주의사항, yt-dlp 업데이트 안내를 화면에 표시합니다. ## 7. 사용 범위 본인이 만든 영상, 허락받은 영상, CC 라이선스 영상 등 정당한 권한이 있는 콘텐츠에만 사용해야 합니다. YouTube 약관상 공개 서버로 배포하는 것은 권장하지 않으며, 로컬 전용으로 설계했습니다.
JavaScript
복사

2-2. 기존 프로그램의 기능

•
다운로드 엔진: yt-dlp + ffmpeg
•
형식 3가지
◦
1080p: bv*[height<=1080]+ba/b[height<=1080]/best
◦
720p: bv*[height<=720]+ba/b[height<=720]/best
◦
MP3: ba/b → FFmpegExtractAudio mp3 192kbps
•
공통 옵션: noplaylist, nocheckcertificate, ignoreerrors, progress_hooks
•
중지: progress hook에서 취소 플래그를 확인해 다운로드 중단
•
저장: 사용자가 고른 폴더에 직접 저장

2-3. 클린룸 재구성 원칙

•
분석과 구현을 분리함
◦
분석 결과는 SPEC.md(기능 명세)로만 정리함
◦
구현은 명세를 기준으로 처음부터 새로 작성함
•
추출한 원본 조각과 문자열(re/ 폴더)은 제3자 코드이므로 로컬에만 보관함
◦
.gitignore로 저장소 업로드 제외
•
명세에서 관찰한 사실과 추론한 내용을 구분해 표시함
•
원본 기능은 유지하되 UI, 문구, 코드는 새로 작성함

2-4. 실패 분석과 로그 기록

•
오류 메시지와 경고 로그를 규칙표로 분류함
◦
비공개, 연령 제한, 봇 확인, 지역 제한, 저작권, 삭제, 라이브, 화질 없음
◦
ffmpeg 없음, 변환 실패, 429(요청 과다), 403(접근 거부), 추출기 오류
◦
네트워크, 디스크 부족, 파일 잠김, yt-dlp 노후
•
화면에 원인과 해결 방법을 표시하고 "실패 로그 받기" 버튼을 제공함
•
실패마다 로그 파일 2종을 기록함
◦
logs/<시각>_<작업ID>.log: 진단, 환경, 진행 로그, Traceback
◦
logs/failures.jsonl: 실패 1건당 1줄 누적
•
사용자가 직접 중지한 작업은 실패로 기록하지 않음
•
실제 테스트에서 놓친 메시지 2건을 규칙에 추가함
◦
"This video is unavailable"
◦
"has not made this video available in your country"

3. 깃허브 배포

[결과물]https://roughkyo.github.io/youtubedown/ (첫 화면의 “exe 내려받기” 버튼 클릭)

3-1. 서버 배포 대신 exe를 선택해야 했던 이유

•
Supabase, Vercel 같은 서버 배포는 이 앱에 맞지 않음
◦
서버에서 다운로드하면 다른 사람의 다운로드를 대신 처리하는 공개 서비스가 됨
◦
YouTube 약관상 공개 서버 배포를 권장하지 않음
◦
서버 IP가 YouTube 봇 차단 대상이 되기 쉬움
•
결론: 각자 자기 PC에서 실행하고, 설치 안내는 웹 페이지로 제공함
◦
데이터베이스나 로그인이 필요 없으므로 Supabase 연동도 불필요함

3-2. 단일 exe 빌드

•
PyInstaller onefile로 YTDownloader.exe 생성
◦
Python, yt-dlp, yt-dlp-ejs, ffmpeg, 웹 화면을 모두 포함함
◦
Python이나 ffmpeg 설치 없이 더블클릭으로 실행 가능
•
실행 흐름
◦
검은 콘솔 창이 실행되고 브라우저에서 http://127.0.0.1:8765가 열림
◦
콘솔 창을 닫으면 서버가 종료됨
◦
이미 실행 중이면 새로 띄우지 않고 브라우저만 다시 열림
•
실패 로그는 exe 옆 logs 폴더에 저장됨
•
--check 옵션으로 구성 요소 확인 가능

3-3. 사용 방법 및 특이점

•
안내 페이지에서 "exe 내려받기" 버튼 클릭하기
•
"Windows의 PC 보호" 창이 출력되면 추가 정보 → 실행 클릭하기
◦
서명하지 않은 무료 프로그램이라 출력되는 경고임
•
브라우저 화면에서 YouTube 링크를 붙여 넣고 형식 선택하기
•
다운로드가 자꾸 실패하거나 업데이트 안내가 출력되면 새 exe로 교체하기

[특이점1]매주 자동 빌드

•
GitHub Actions(release.yml)가 매주 월요일 새 exe를 빌드해 Releases에 게시함
◦
yt-dlp 버전이나 코드가 바뀐 경우에만 새 릴리스 생성
◦
배포용 exe에는 LGPL 라이선스 ffmpeg(BtbN 빌드)를 사용함

[특이점2]동시작업은 최대 2대까지

3-4. 주의사항

•
교육용 목적에 한해 사용하기
◦
본인이 만든 영상, 허락받은 영상, CC 라이선스 영상처럼 이용 권한이 있는 콘텐츠만 받기
◦
재배포·재업로드·상업적 이용은 하지 않기