Nodejs Docker 프로젝트_Twitch 다운로더 만들기

목차

개발의 목적

필자는 트위치나 방송을 잘보는 편은 아니지만 박김례의 전장이라는 방송은 구독까지할 정도로 잘 챙겨보고 있다. 다만 필자가 일하는 곳이 인터넷이 엄청 원활한 곳은 아니다보니 FHD로 보는 것도 버거워서 방송을 틀면서 다른 인터넷 작업을 할 수 없었다. 그래서 다시보기를 다운로드할 수 있는 방법을 찾아보다가 트위치링크같은 프로그램을 찾아보기도 했었다. 다만 필자의 경우에는 오류가 간혹나기도해서 절대적인 방법이 되지는 못했다. 결국에는 다른 기기에서도 호환성을 타지않고 쉽게 다운로드할 수 있고 명령어로 쉽게 실행시킬 수 있는 Docker로 다운로더 프로그램을 만들게 되었다. 이번 개발로 ffmpeg에대해 공부할 수 있는 기회도 되었고 후에 batch등에 추가해서 자동으로 영상을 다운로드 할 수 있게 만들어봐야겠다는 생각도 들었다.

결론

필자가 생각한대로 잘 작동되었다. 다만 박김례의 전장뿐만 아니라 다양한 트위치 영상을 다운로드 받을 수 있도록 string,thread 옵션이나 변수 구조에도 여러므로 변경을 했었다. 다만 ffmpeg가 Docker에서 하드웨어 가속을 사용하지 못하기에 다운시간이 조금 걸리는 편인 것 같다. 지금까지 10편 정도를 다운로드 했었는데, 오류가 하나도 없었던 점은 좋았다. 앞으로도 자주 쓸 것 같고 라즈베리파이나 PC에서 자동으로 새 다시보기가 생기면 FTP를 통해 PLEX 서버로 자동으로 다운로드할 수 있도록 만들어보는 것도 생각해봐야겠다. readme.md파일을 미리 작성하니 블로그 글쓰기가 훨씬 수월했다. 앞으로도 readme.md를 잘 활용해야겠다.

프로젝트 빌드가 아닌 Dockerhub에서 바로 내려받고 싶다면 아래 Dockerhub에서 소개된대로 사용하면된다!

Github 링크
Dockerhub 링크

출력결과

1
2
3
4
5
6
7
8
9
10
11
12
13
target link is : https://d2nvs31859zcd8.cloudfront.net/058492dd4ece5e3f9cb2_bbaktube_42450100382_1619590815/chunked/index-dvr.m3u8
File name is : BBAK2021.mp4
Queueing 211 segment(s)
Received: https://d2nvs31859zcd8.cloudfront.net/058492dd4ece5e3f9cb2_bbaktube_42450100382_1619590815/chunked/0.ts
(0~211 조각을 다운로드 시도 - 로그가 길어져 생략함)
Received: https://d2nvs31859zcd8.cloudfront.net/058492dd4ece5e3f9cb2_bbaktube_42450100382_1619590815/chunked/211.ts
All segments received, stopping
Spawning FFMPEG ffmpeg -y -loglevel warning -i /tmp/hls-downloader/1624414273697.ts -c copy -bsf:a aac_adtstoasc BBAK2021.mp4

# 도커를 실행한 디렉토리에 BBAK2021.mp4 파일이 생김

Complete

개발에 사용할 도구들

Docker

Docker는 기존 sudo npm install **** 처럼 프로그램/모듈을 설치하는 것이 아닌 이미 세팅된 프로그램을 리눅스 컨테이너로 불러와 사용하는 것이다. 그 덕분에 세팅하는 시간도 줄어들고 프로그램을 관리할때도 장점이 많다. 다만 컨테이너별로 IP가 할당되기에 다른 컨터이너와 통신을 하려면 조금 까다라운 부분도 있다. 필자도 Docker 장점을 처음에는 잘 몰랐지만 이번에 개발을 하며 Docker을 편리함을 많이 느낄 수 있었다.

Visual Studio Code

Visual Studio Code는 리눅스 리눅스의 Vim같은 텍스트 에디터지만 Visual studio처럼 인텔리센스와 내장된 터미널이 있다는 것이 큰 장점이다. 다만 자바나 파이썬같은 컴파일러는 언어마다 따로 설치해야한다. Visual Studio Code는 어디까지나 쉽게 코딩하고 디버깅할 수 있게 도와주는 도구지 IDE가 아니다! 필자도 Visual Studio Code의 여러 종류의 플러그인을 같이 사용해서 다재다능하게 사용할 수 있다는 점이 강점이라고 생각한다.

Nodejs

Nodejs는 자바스크립트 런타임이다. 주로 서버에 사용한다는 느낌도 있지만 의외로 NPM의 광활한 라이브러리 덕분에 여러가지 프로젝트에서 활용될 수 있다. 필자도 C나 파이썬도 필요에 따라 사용하지만 nvm과 npm 등이 Nodejs를 더 간편하고 가치있게 만드는 것이라고 생각한다.

개발 과정

  1. 윈도우에 처음 Docker를 설치한다면 공식 Docker 가이드를 따라 설치해보자

  2. 이제 Visual Studio Code에 Docker 플러그인을 설치하자

  3. 평소 Nodejs 개발처럼 폴더를 만들고 코드를 실행할 환경을 만들어보자. 이번에는 필자의 경우를 예시로 들어보았다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 디렉토리 폴더로 안으로 이동이후!

    cd /Wanted_directory

    # 빈 app.js 파일 생성

    npm init # package.json 파일을 생성한다.

    # package.json에 스크립트는 node app.js로 입력해주자
    # "scripts": {
    # "test": "node app.js"
    # }

    npm install --save node-hls-downloader
    # package.json에 의존성이 잘 기록되는지 확인하자!
  4. 다음처럼 app.js 파일을 입력해주자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
이 코드는 트위치 다시보기를 저장하기위한 코드입니다. 필자가 일하는 곳이 인터넷이 불안정하다보니 모니터 해상도대비 부족한 화질로 방송 다시보기를 보기에는 힘든 점이 많았습니다.
그런 점을 개선하고자 지난 방송을 저장할 수 있도록 코딩을 하고 쉽고 빠르게 작동시킬 수 있도록 Docker로 만들었습니다. 저장할 다시보기의 이미지 링크를 바탕으로 현재 디렉토리에 다시보기 MP4 파일을 저장합니다.
필자의 코딩실력 부족으로 인해 /storyboards까지 자동으로 편집하는 코드는 만들지 못했습니다. 그래서 유저가 /storyboard 앞 숫자까지의 string 수를 변수로 같이 입력해줘야합니다.
string 수는 글자수 세기 사이트(ex. https://www.saramin.co.kr/zf_user/tools/character-counter) 등을 이용해서 계산하면됩니다.

-e string = /storyboard 앞까지의 string 수
-e link = 저장할 다시보기의 썸내일 이미지 주소
-e name = 저정할 파일의 이름(MP4)
-e thread = 사용할 쓰레드의 수

예시:

docker run -v ${PWD}:/usr/src/app -i --rm --name app -e thread=4 -e string=91 -e link=https://d2nvs31859zcd8.cloudfront.net/058492dd4ece5e3f9cb2_bbaktube_42450100382_1619590815/storyboards/1003549824-strip-0.jpg -e name=BBAK2021 swoho0325/twitch-download
*/

const download = require("node-hls-downloader").download;

//Docker에서 변수 받아오기
const link = process.env.link;
//ex.https://d1m7jfoe9zdc1j.cloudfront.net/e666d04affe8bf5b0147_bbaktube_42367451261_1623657470/storyboards/1055780298-strip-0.jpg
const string = process.env.string;
//ex.91
const name = process.env.name;
//ex.20210617BBAK
var thread = parseInt(process.env.thread);
//ex.4

//ffmpeg에 맞게 변수 가공
var changed_link = link.substring(0,string) + "chunked/index-dvr.m3u8";
console.log("target link is : " + changed_link);
//target link is : https://d1m7jfoe9zdc1j.cloudfront.net/e666d04affe8bf5b0147_bbaktube_42367451261_1623657470/chunked/index-dvr.m3u8

const changed_name = name + ".mp4"
console.log("File name is : " + changed_name);
//File name is : 20210617BBAK.mp4

// Await를 이용해 다운로드가 다 끝날때까지 기다리고 컨테이너를 완료함.
// 필자 컴퓨터(i5-7500T)로 4쓰레드, 2쓰레드 해보았는데, 쓰레드 수보다는 인터넷 속도가 다운속도에 더 큰 영향을 주는 것 같다. 더 많은 쓰레드를 쓰고 싶다면 concurrency를 올리면된다.
async function asyncCapture(){
await download({
quality: "best",
concurrency: thread,
// httpHeaders: "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Safari/537.36",
outputFile: changed_name,
streamUrl: changed_link,
});

console.log("Complete");
}

asyncCapture();
  1. node app.js 등의 명령으로 잘 작동하는 것을 확인한 후에는 Visual Studio의 커맨드 창에서 Dockerfile 생성을 해보자. F1 누르고 add docker files to workspace를 선택하면된다.
  2. 파일 생성이 완료되면 터미널로 넘어간다. package.json이 의존성이나 스크립트 등이 잘 반영되어있는지 꼭 확인하자!
  3. ffmpeg를 Docker 내에서 사용하기 위해서 Dockerfile에서 ffmpeg를 다운로드하는 명령을 추가하자
1
2
3
4
5
6
# Dockerfile에 다음처럼 추가하자
COPY ["package.json", "package-lock.json*", "npm-shrinkwrap.json*", "./"]

COPY --from=mwader/static-ffmpeg:4.4.0 /ffmpeg /usr/local/bin/
COPY --from=mwader/static-ffmpeg:4.4.0 /ffprobe /usr/local/bin/
COPY --from=mwader/static-ffmpeg:4.4.0 /qt-faststart /usr/local/bin/
1
2
3
4
5
6
7
8
# app.js와 package.json이 있는 디렉토리에서! 

docker build -t "이미지 이름" .
docker images # 이미지가 잘 생성되었는지 확인한다.
docker run -v ${PWD}:/usr/src/app -i --rm --name "컨테이너 이름" -e thread="사용할 쓰레드 수" -e string="썸내일 이미지 링크에서 유효한 링크의 글자수(app.js쪽 설명참조!)" -e link="트위치 다시보기의 썸내일 이미지 링크" -e name="저장될 파일 이름" "이미지 이름"
# docker rmi "이미지 이름"
# docker rm -f "컨테이너 이름"
# 혹시라도 내용 변경을 위에 새로 빌드해야할때는 위 2개의 명령으로 완전히 지우고 새로 이미지를 만들어보자
  1. 결과창에 출력결과처럼 잘 나오는지 확인해보자

시행착오

  1. 이미 /storyboard의 뒤를 지운 링크를 만들었는데, 그대로 붙여넣기해서 사용하지 왜 글자수를 세서 입력하는 과정이 필요없다고 생각하실 수 있습니다. 저도 처음에는 그대로 편집한 링크를 넣는 방식으로 했는데 2개,3개 다운로드 할때부터 링크를 편집하고 복사하기에 너무 시간이 많이 들었고, 같은 트위치 스트리머내의 다시보기의 글자수 갯수는 모두 일치하기에 한번 글자수 세는 것이 2개이상의 다시보기 다운로드에는 더 효율적이라 생각하고 여러 영상을 다운로드 한다는 것에 좀 더 초점을 맞춰서 글자수 + 원본링크로 변수를 구성하게 되었습니다.
  2. 반드시 다시보기의 썸네일 링크를 복사해야합니다! 예시
  3. 만약에 ffmpeg 관련한 오류가 뜬다면 Dockerfile에 다음처럼 적혀있도록 해야합니다!
1
2
3
COPY --from=mwader/static-ffmpeg:4.4.0 /ffmpeg /usr/local/bin/
COPY --from=mwader/static-ffmpeg:4.4.0 /ffprobe /usr/local/bin/
COPY --from=mwader/static-ffmpeg:4.4.0 /qt-faststart /usr/local/bin/
  1. (번외)PowerShell에 결과 창 복사시 명령어 | clip을 사용한다면 콘솔창에 찍히는 게 없는 것이 정상입니다!

참고한 자료들과 같이보기 좋은 자료들

  1. https://meonol.tistory.com/97
  2. https://hub.docker.com/r/mwader/static-ffmpeg/
  3. https://github.com/wader/static-ffmpeg
  4. https://stackoverflow.com/questions/50693091/ffmpeg-install-within-existing-node-js-docker-image
  5. https://www.npmjs.com/package/m3u8-to-mp4
  6. https://www.npmjs.com/package/ffmpeg-static
  7. https://uaremine.tistory.com/11
  8. https://svrstudy.tistory.com/62
  9. https://www.npmjs.com/package/node-hls-downloader