환경: Synology DS918+ / PMS v1.43.0.10492 / SJVA 에이전트 최종 업데이트: 2026-03-03
- 문제: PMS v1.43의
libfreeimage.so가 모든 WebP 이미지 (VP8X, VP8, VP8L)에서 EXIF 파싱 시 NULL 역참조 → SIGSEGV 크래시 - 해결: 메타데이터 내 모든 WebP → JPEG 변환 (VP8→VP8 재인코딩은 v1.43에서 효과 없음)
- 도구:
fix_vp8x.py— ffmpeg 기반 WebP→JPEG 일괄 변환 스크립트 - SJVA 패치:
agent_base.py+module_ktv.py+module_yaml_base.py3개 파일 수정 필요 ⚠️ PMS 버전 의존: v1.43에서는 모든 WebP 크래시. v1.42 이하에서는 VP8X만 문제일 수 있음 (libfreeimage.so 버전 차이)
적용 방법 (Quick Start) — 클릭하여 펼치기
# 1. ffmpeg-static 설치 (Synology 기본 ffmpeg엔 libwebp 없음)
# https://johnvansickle.com/ffmpeg/ 에서 다운로드
sudo cp ffmpeg /usr/local/bin/ffmpeg-static
# 또는 패키지 센터 ffmpeg7 설치 후 심볼릭 링크:
# sudo ln -s /volume1/@appstore/ffmpeg7/bin/ffmpeg7 /usr/local/bin/ffmpeg-static
# 2. fix_vp8x.py 배포 (소스 Gist에서 다운로드)
sudo cp fix_vp8x.py /usr/local/bin/fix_vp8x.py
# 3. 전체 스캔 실행
python3 /usr/local/bin/fix_vp8x.py --days 0
# 4. DSM 작업 스케줄러에 daily cron 등록 (Butler 시작 전 실행)
# python3 /usr/local/bin/fix_vp8x.py --days 3 --quiet >> /var/log/fix_vp8x.log 2>&1
# 5. (선택) SJVA 에이전트 패치 — 신규 VP8X 유입 차단
# 소스 Gist의 agent_base.py, module_ktv.py, module_yaml_base.py를
# SjvaAgent.bundle/Contents/Code/ 에 덮어쓰기 후 PMS 재시작
# 패치 보호: git update-index --assume-unchanged Contents/Code/agent_base.py ...| 날짜 | 상태 | 내용 |
|---|---|---|
| 2026-02-22 | 🔴 크래시 15회 | 최초 발생, VP8X 1,101개 변환, 안정화 |
| 2026-02-24~26 | 🔴 재발 | SJVA/Butler 스케줄 충돌 → 스케줄 조정 |
| 2026-02-28 | 🟡 패치 적용 | 키효님 agent_base.py 패치 배포 |
| 2026-03-01 | 🔴 재발 | 패치 미작동 발견 (module 오버라이드) |
| 2026-03-01 | 🟢 해결 | GDB 분석 → 모든 WebP 크래시 확정 → 86,917개 JPEG 일괄 변환 |
| 2026-03-01 | 🟢 안정 | module 패치 완료, watchdog 배포, Butler 테스트 통과 |
| 2026-03-03 | 🟢 2일째 크래시 0건 | 완전 해소 확인 |
- Plex Butler 실행 시 UltraBlurProcessor가 WebP 이미지를 처리하다 SIGSEGV 크래시
- 자동 재기동 → 동일 이미지 재처리 → 재크래시 (
79분 간격 반복) - 최악의 경우 한 세션에 15회 연속 크래시
libfreeimage.so + 0x43e74 — WebP EXIF 파싱 시 NULL 포인터 역참조 → SIGSEGV
RAX = 0x66697845 ("Exif") — EXIF 매직넘버 처리 중 크래시
- PMS v1.43의 FreeImage 라이브러리가 모든 WebP 포맷에서 EXIF 파서를 호출
- EXIF 데이터가 없으면 NULL 포인터 → 크래시
- VP8X뿐 아니라 VP8, VP8L 모두 해당 (v1.43 기준)
- v1.42 이하에서는 VP8X만 문제일 수 있음 (libfreeimage.so 버전 차이)
키효님의 agent_base.py 패치(VP8X→VP8 변환)가 실제로 호출되지 않았습니다:
AgentBase(agent_base.py) — safe_image_content() 정의 ← 여기에 패치
└─ ModuleYamlBase(module_yaml_base.py) — set_data_media() 오버라이드 → HTTP.Request() 직접 호출
└─ ModuleKtv(module_ktv.py) — HTTP.Request() 직접 호출 (14곳)
해결: 3개 파일 모두 HTTP.Request(URL).content → self.safe_image_content(URL) 교체 필요
WebP 포맷 종류 및 Plex 처리 결과
| 헤더 | 설명 | PMS v1.42 이하 | PMS v1.43 |
|---|---|---|---|
VP8 |
단순 손실 압축 WebP | 정상 | 크래시 |
VP8L |
단순 무손실 WebP | 정상 | 크래시 |
VP8X |
확장 WebP (투명도, ICC 등) | 크래시 | 크래시 |
| JPEG | — | 정상 | 정상 |
fix_vp8x.py를 사용합니다.
# 전체 스캔
python3 fix_vp8x.py --days 0
# 최근 3일 증분 스캔 (daily cron용)
python3 fix_vp8x.py --days 3 --quiet
# 확인만 (변환 안 함)
python3 fix_vp8x.py --dry-run
# 경로 지정
python3 fix_vp8x.py --base "/volume1/.../Metadata"DSM 작업 스케줄러 등록 방법
⚠️ Synology/etc/crontab은 DSM 업데이트 시 초기화됩니다. 반드시 DSM 작업 스케줄러 사용.
DSM 제어판 → 작업 스케줄러 → 생성 → 예약된 작업 → 사용자 정의 스크립트
[일반] 작업명: Plex VP8X Fix / 사용자: root / 활성화: ✓
[스케줄] 매일, Butler 시작 전 실행 (예: 06:15)
[작업 설정]
python3 /usr/local/bin/fix_vp8x.py --days 3 --quiet >> /var/log/fix_vp8x.log 2>&1
ffmpeg-static 설치 (Synology)
Synology 기본 ffmpeg에는 libwebp 인코더가 없습니다. 정적 빌드를 설치해야 합니다.
# johnvansickle.com 정적 빌드 다운로드
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar xf ffmpeg-release-amd64-static.tar.xz
sudo cp ffmpeg-*-static/ffmpeg /usr/local/bin/ffmpeg-static
# 또는 패키지 센터 ffmpeg7 설치 후 심볼릭 링크
sudo ln -s /volume1/@appstore/ffmpeg7/bin/ffmpeg7 /usr/local/bin/ffmpeg-static
# 확인
/usr/local/bin/ffmpeg-static -encoders 2>/dev/null | grep webp소스 Gist에서 agent_base.py, module_ktv.py, module_yaml_base.py를 다운로드하여 적용합니다.
현재 에이전트 패치는 VP8X → VP8 WebP 변환입니다 (키효님 원본 방식).
- v1.42 이하: 이것만으로 크래시 방지 충분
- v1.43: VP8 WebP도 크래시하므로, fix_vp8x.py daily cron이 후속으로 JPEG 변환 필요
# 1. 파일 덮어쓰기
cd "SjvaAgent.bundle/Contents/Code/"
# agent_base.py, module_ktv.py, module_yaml_base.py 복사
# 2. SJVA 업데이트 시 덮어쓰기 방지
cd "SjvaAgent.bundle"
git update-index --assume-unchanged Contents/Code/agent_base.py
git update-index --assume-unchanged Contents/Code/module_ktv.py
git update-index --assume-unchanged Contents/Code/module_yaml_base.py
# 3. PMS 재시작패치 상세 — 변경 내용
agent_base.py (키효님 원본):
webp_chunk(),is_webp_vp8x(),ffmpeg_convert_vp8_webp(),safe_image_content()4개 메서드 추가set_data_media()에서HTTP.Request()→safe_image_content()교체- 변환: VP8X → VP8 WebP (
ffmpeg -c:v libwebp)
module_ktv.py (14곳 변경):
# 변경 전
ProxyClass(HTTP.Request(item['value']).content, sort_order=...)
# 변경 후
ProxyClass(self.safe_image_content(item['value']), sort_order=...)module_yaml_base.py (set_data_media() 내 2곳 변경):
# 변경 전
meta[media['url']] = Proxy.Preview(HTTP.Request(media['thumb']).content, ...)
# 변경 후
meta[media['url']] = Proxy.Preview(self.safe_image_content(media['thumb']), ...)[1단계] SJVA 에이전트 패치 (VP8X→VP8, 신규 유입 차단) — 이것만으로 충분
[2단계] fix_vp8x.py daily cron (보험 — 기존 VP8X 파일 JPEG 정리)
[1단계] SJVA 에이전트 패치 (VP8X→VP8, 신규 VP8X 유입은 차단)
[2단계] fix_vp8x.py daily cron (핵심 — 모든 WebP→JPEG 변환)
[3단계] plex_crash_watchdog.py 5분 크론 (크래시 시 코어 덤프 분석→변환→정리)
[4단계] watch_pms.sh 1분 크론 (PMS 자동 재시작)
v1.43에서 크래시가 계속 발생할 경우, agent_base.py의 safe_image_content()를 JPEG 변환으로 변경하면 신규 유입 시점에서 바로 JPEG로 저장됩니다.
| 라이브러리 | WebP 파일 수 | 변환 결과 | 소요 시간 |
|---|---|---|---|
| Movies | 10,563 | 전체 성공 | 5분 31초 (31.9/s) |
| TV Shows | 76,354 | 전체 성공 | 122분 (10.5/s) |
| 합계 | 86,917 | fail 0 | ~128분 |
| 기간 | 크래시 횟수 | 비고 |
|---|---|---|
| 02-22 | 15회 | 최초 발생 |
| 02-24~26 | 10회+ | 스케줄 충돌 재발 |
| 02-28 | 0회 | agent_base.py 패치 (실제 미작동) |
| 03-01 07시 | 9회 | 패치 미작동으로 재발 |
| 03-01 11시 | 3회 | 코어 덤프 분석용 |
| 03-01 17시 ~ 현재 | 0회 | 🟢 일괄 변환 후 완전 해소 |
6. 상세 분석 — 최초 로그 분석 (2026-02-22)
2026-02-22 04:49:06 - 기동 (WAL에서 659 프레임 복구 ← 비정상 종료 흔적)
...
2026-02-22 04:57:09 - [UltraBlurProcessor] Failed to decode image data ← 15회 연속
2026-02-22 04:57:10 - Crash: Crash reporting disabled
Plex Butler 시작 (예약 시간)
→ UltraBlurProcessor: WebP 이미지 처리 시도
→ Failed to decode image data (연속)
→ SIGSEGV 크래시
→ 자동 재기동 → 동일 이미지 재처리 → 재크래시 (7~9분 간격 루프)
Plex 클라이언트(Plex Web, Plexamp 등)에서 포스터 배경에 부드러운 색상 그라데이션을 표시하기 위해 이미지 4개 코너에서 색상을 추출하는 내부 컴포넌트.
7. 상세 분석 — VP8X 확인 스크립트
# check_webp.py — WebP 파일 개수 확인
import os
META_BASE = '/volume5/PlexMediaServer/AppData/Plex Media Server/Metadata'
LIBS = ['Movies', 'TV Shows']
total = vp8x = webp = 0
for lib in LIBS:
lib_path = os.path.join(META_BASE, lib)
for root, dirs, files in os.walk(lib_path):
for fname in files:
fpath = os.path.join(root, fname)
if os.path.islink(fpath):
continue
try:
total += 1
with open(fpath, 'rb') as f:
h = f.read(16)
if len(h) >= 12 and h[:4] == b'RIFF' and h[8:12] == b'WEBP':
webp += 1
if len(h) >= 16 and h[12:16] == b'VP8X':
vp8x += 1
except:
pass
print(f'전체: {total} / WebP: {webp} / VP8X: {vp8x}')8. 상세 분석 — inotify 및 VP8 vs JPEG 비교
# 커널 inotify 지원: O
cat /proc/sys/fs/inotify/max_user_watches # → 524288
# inotify-tools: 없음 / pip: 없음
# ctypes 직접 호출: 가능하나 복잡도 높아 daily cron 유지 결정| 항목 | VP8 WebP (ffmpeg) | JPEG (ffmpeg/ImageMagick) |
|---|---|---|
| PMS v1.43 | 크래시 | 정상 |
| PMS v1.42 이하 | 정상 | 정상 |
| 파일 크기 | 더 작음 | 더 큼 |
| 변환 성능 | 보통 | 빠름 |
결론: v1.43에서는 JPEG만 안전. v1.42 이하에서는 VP8도 가능.
9. 스케줄 최적화 이력
- Butler 05:00~06:00, VP8X Fix 06:00 (동시!) → 04:45로 앞당김
- SJVA 대량 갱신일 06:53까지 실행 → VP8X Fix 07:15 / Butler 07:30~08:30
| 시간 | 작업 |
|---|---|
| 06:15 | fix_vp8x.py v4 (WebP→JPEG) |
| 07:00~08:00 | Plex Butler |
| 08:30 | Plex DB Repair |
Butler 설정 주의: Preferences.xml 직접 편집은 PMS 재시작 시 메모리 값으로 덮어씀. 반드시 API로 변경:
curl -X PUT "http://localhost:32400/:/prefs?ButlerStartHour=7&ButlerEndHour=8&X-Plex-Token=TOKEN"
10. fix_vp8x.py 버전 이력
| 버전 | 날짜 | 주요 변경 |
|---|---|---|
| v1 | 02-22 | 최초 작성, VP8X→JPEG (ImageMagick) |
| v2 | 02-22 | extract_bundle_hash 버그 수정 |
| v3 | 02-25 | --quiet WARNING 로그, thread-safe tmp, Discord 웹훅 UA |
| v4 | 03-01 | 모든 WebP 탐지, ffmpeg-static WebP→JPEG (-q:v 2) |
- Plex 공식 포럼 PM-2597: UltraBlurProcessor 로그 스팸 (v1.41.5에서 수정, 크래시와 별도)
- 현재 v1.43.0.10492 기준 WebP 크래시 관련 공식 픽스 없음
- 패치 원작자: 키효님 (SJVA Discord, 2026-02-23) — agent_base.py VP8X→VP8 변환