yt-dlp 를 사용하여 구현하기 (상세)

강정우·2025년 10월 17일
0

기타

목록 보기
3/4
post-thumbnail

yt-dlp 파일 작성

1. systemd 서비스 설정

yt-dlp 설치 및 경로 설정

yt-dlp 를 반드시 설치해야하는데, pipx로 설치하면 yt-dlp는 보통 ~/.local/bin/yt-dlp 또는 pipx venv 경로에 다
따라서 서비스에 PATH를 명시하고 스크립트에 절대경로를 없애거나 또는 정확한 절대경로로 수정 (/home/ubuntu/.local/bin/yt-dlp) 하면 된다.

서비스 파일(.ini) 작성 예시

[Unit]
Description=HLS live stream author.KJW
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/live-stream
Environment="PATH=/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
Environment=PYTHONUNBUFFERED=1
ExecStart=/usr/bin/bash -lc /opt/live-stream/live-stream.sh
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=false
ProtectSystem=full
ReadWritePaths=/var/www/videos/hls/live/720p /opt/live-stream
StandardOutput=journal
StandardError=inherit

[Install]
WantedBy=multi-user.target

권한/마운트 이슈를 우회하고 진단도 쉬운 형태로 설정.

ExecStart=/usr/bin/bash -lc /opt/live-stream/live-stream.sh

참고로 -l(login)은 /etc/profile 등을 읽어서 PATH가 더 풍부해지지만, 사용자 셸 설정(~/.bashrc)은 기본으론 안 읽힐 수 있다. 그래서 서비스 파일에서 Environment=PATH=...를 명시하는 것이다.

스크립트 파일 작성 예시

#!/usr/bin/env bash
set -Eeuo pipefail

VIDEO_URL="${VIDEO_URL:-https://www.youtube.com/watch?v=채널_id}"
COOKIES="${COOKIES:-/opt/live-stream/cookies.txt}"
OUTPUT_DIR="${OUTPUT_DIR:-/var/www/videos/hls/live/720p}"

YTDLP_BIN="${YTDLP_BIN:-$(command -v yt-dlp)}"
FFMPEG_BIN="${FFMPEG_BIN:-$(command -v ffmpeg)}"

if [[ -z "${YTDLP_BIN}" ]]; then
  echo "yt-dlp not found in PATH" >&2; exit 127
fi
if [[ -z "${FFMPEG_BIN}" ]]; then
  echo "ffmpeg not found in PATH" >&2; exit 127
fi

mkdir -p "$OUTPUT_DIR"

RESTART_DELAY=15
UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115 Safari/537.36"
REF="https://www.youtube.com/"

if [[ -s "$COOKIES" ]]; then
  COOKIES_ARG=(--cookies "$COOKIES")
  FFMPEG_COOKIE_ARG=()  # 필요 시 -headers "Cookie: ..." 방식으로 교체
else
  COOKIES_ARG=()
  FFMPEG_COOKIE_ARG=()
fi

while true; do
  echo "[$(date)] Fetching fresh HLS URL from YouTube..."
  if ! HLS_URL="$("$YTDLP_BIN" -g "${COOKIES_ARG[@]}" --no-warnings -f "bv*[height<=720]+ba/b" "$VIDEO_URL")"; then
    echo "[$(date)] yt-dlp failed. Retrying in $RESTART_DELAY sec..."
    sleep "$RESTART_DELAY"; continue
  fi

  if [[ -z "$HLS_URL" ]]; then
    echo "[$(date)] Empty HLS URL. Retrying in $RESTART_DELAY sec..."
    sleep "$RESTART_DELAY"; continue
  fi

  echo "[$(date)] Got HLS URL: $HLS_URL"
  echo "[$(date)] Starting ffmpeg HLS restream..."

  set +e
  "$FFMPEG_BIN" -hide_banner -loglevel warning \
    -user_agent "$UA" -referer "$REF" "${FFMPEG_COOKIE_ARG[@]}" \
    -re -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 15 \
    -rw_timeout 20000000 -timeout 20000000 -seekable 0 \
    -fflags +genpts+discardcorrupt -probesize 15M -analyzeduration 20M \
    -i "$HLS_URL" -c copy -bufsize 20M -max_delay 5000000 \
    -f hls -hls_time 10 -hls_list_size 20 \
    -hls_flags delete_segments+append_list+omit_endlist \
    "$OUTPUT_DIR/index.m3u8"
  CODE=$?
  set -e

  echo "[$(date)] ffmpeg exited with code $CODE. Waiting $RESTART_DELAY sec before restart..."
  sleep "$RESTART_DELAY"
done

쓰기 경로 권한부여

출력 경로(/var/www/videos/hls/live/720p)는 User=ubuntu가 쓰기 가능해야 한다.

sudo mkdir -p /var/www/videos/hls/live/720p
sudo chown -R ubuntu:www-data /var/www/videos
sudo chmod -R 775 /var/www/videos

혹은 서비스에 아래 줄을 넣어주면 되는데,

ReadWritePaths=/var/www/videos/hls/live/720p /opt/live-stream

이 코드는 systemd sandbox 가 쓰기를 허용하는 줄이다.
참고로 디렉터리 자체 권한, 소유권까지 제대로 맞춰줘야 한다.

쿠키/헤더 옵션

작동 후 품질 개선을 위해 쿠키 및 헤더 옵션을 넣어준다.
ffmpeg-cookies 옵션은 name=value; name2=value2 형태가 일반적인데,
-cookies "file=/path" 는 ffmpeg 표준 옵션은 아니니(빌드마다 다를 수 있음) 헤더로 넘기는 방법을 고려하였다.

쿠키 파일을 헤더로 붙이는 예 (Netscape cookies.txt라면 변환 필요)

FFMPEG_COOKIE_ARG=(-headers "Cookie: $(awk 'BEGIN{ORS="; "}$0 !~ /^#/ {print $6"="$7}' "$COOKIES")")

일단 지금처럼 yt-dlp -g로 m3u8을 받아서 -user_agent와 -referer만 맞춰도 동작하는 경우가 많으니, 우선 권한/경로부터 해결하고 필요 시 다듬자.

트러블 슈팅 방법

1. 스크립트와 경로 권한 확인

# 각 경로 구성요소의 권한을 한 눈에 보기
namei -l /opt/live-stream/live-stream.sh

# 퍼미션/소유자 확인
ls -l /opt/live-stream/live-stream.sh
ls -ld /opt/live-stream

조건:
live-stream.sh에 실행 비트가 있어야 함 => -rwxr-xr-x(0755) 추천
/opt/opt/live-stream 디렉터리에 실행 권한이 있어야 User=사용자명 가 경로를 탐색(traverse) 가능 (보통 755)

수정

sudo chown 사용자명:사용자명 /opt/live-stream/live-stream.sh /opt/live-stream
sudo chmod 0755 /opt/live-stream /opt/live-stream/live-stream.sh

참고: 디렉터리의 x 권한은 “들어갈 수 있음”이다. 따라서 아무리 파일을 755로 바꿔도, 디렉터리가 700이면 여전히 Permission denied가 뜰 수 있다.

2) CRLF(윈도우 개행) 및 shebang 확인

윈도우에서 만든 스크립트면 커널이 인터프리터를 못 찾아서 문제를 낼 수 있다.

head -n1 /opt/live-stream/live-stream.sh
file /opt/live-stream/live-stream.sh

첫번째 명령어는 쉬뱅인 #!/usr/bin/env bash 가,
두번째 명령어는 with CRLF line terminators 가 보이면 안 된다.

캐리지 리턴, 라인 피드 정리를 위해선 아래 명령어를 입력하면 된다.

sudo sed -i 's/\r$//' /opt/live-stream/live-stream.sh

3) noexec 마운트 여부 확인

참고로 그럴일은 없겠지만 optnoexec로 마운트 되어있으면 실행 자체가 막힌다.
따라서 아래 명령어를 실행한 뒤,

findmnt -no TARGET,OPTIONS /opt
# 또는
mount | grep ' /opt '

noexec 가 보이면 가급적 스크립트를 noexec 아닌 경로(예: /usr/local/bin)로 옮기거나, 서비스에서 인터프리터로 실행하면 된다.
ExecStart=/usr/bin/bash /opt/live-stream/live-stream.sh
참고로 이 방식은 스크립트에 x 비트가 없어도 동작한다. 대신 보안상 최선은 아님.

정리.

# 1) 권한/소유/개행 정리
sudo chown ubuntu:ubuntu /opt/live-stream /opt/live-stream/live-stream.sh
sudo chmod 0755 /opt/live-stream /opt/live-stream/live-stream.sh
sudo sed -i 's/\r$//' /opt/live-stream/live-stream.sh

# 2) 출력 디렉터리 준비
sudo mkdir -p /var/www/videos/hls/live/720p
sudo chown -R ubuntu:www-data /var/www/videos
sudo chmod -R 775 /var/www/videos

혹은 서비스 파일에 명시

# 3) /opt noexec 여부 점검(필요 시만 보통은 필요 없을꺼임.)
findmnt -no TARGET,OPTIONS /opt

# 4) 서비스 파일 수정(예: /etc/systemd/system/live-stream.service)
#   - ExecStart=/usr/bin/bash -lc /opt/live-stream/live-stream.sh
#   - Environment="PATH=/home/ubuntu/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"

# 5) systemd 반영 및 재기동
sudo systemctl daemon-reload
sudo systemctl restart live-stream
sudo journalctl -u live-stream -e --no-pager
profile
智(지)! 德(덕)! 體(체)!

0개의 댓글