Skip to content

changmink/MM

Repository files navigation

Media Manager

개인용 로컬 네트워크 멀티미디어 서버. 이미지·동영상·음악을 업로드·탐색·스트리밍하고, URL에서 직접 다운로드하고, TS를 MP4로 영구 변환한다.

  • 인증 없음 — 로컬 네트워크/단일 사용자 전제
  • Go 단일 바이너리 + ffmpeg — Docker 컨테이너 하나로 배포
  • 데이터는 Docker named volume에 영속 저장 (/data)

현재 버전: 0.0.2 — 이미지/움짤 변환(PNG → JPG, 움짤 → animated WebP) + 다중 선택 UX 추가. 자세한 설계는 SPEC.md 참조.


주요 기능

파일 관리

  • 업로드 (multipart, 드래그 앤 드롭)
  • 폴더 트리 탐색 (사이드바) + 현재 폴더 리스트/그리드
  • 파일·폴더 rename (확장자 고정), 삭제 (폴더는 재귀)
  • 폴더 생성 모달 — 사이드바 헤더의 "+ 새 폴더" 진입 (현재 browse 경로 기준 생성)
  • 폴더 작업 동선은 사이드바 트리 — 트리 노드 hover 시 ✎ rename / 🗑 삭제 노출
  • 폴더 이동(DnD) — 트리 노드 또는 메인 리스트 폴더 행을 다른 트리 노드/breadcrumb 위로 끌어 놓기. 자기 자신/자손/동일 부모로의 이동은 거부, 충돌 시 409
  • 다중 선택 + 일괄 작업 — 카드/행 체크박스 또는 빈 영역 rubber-band 드래그로 visible 항목 일괄 선택, 사이드바 폴더로 한 번에 이동(폴더는 단건 이동만)

이미지 / 동영상 / 음악

  • 이미지 섬네일 자동 생성 (200×200 JPEG, .thumb/ 사이드카)
  • 동영상 섬네일 + duration 오버레이 (ffmpeg, 50%/25%/75% 프레임 폴백)
  • HTTP Range 스트리밍 (MP4/MKV/AVI/MP3/FLAC/AAC/OGG/WAV/M4A)
  • TS 파일: 실시간 remux 스트리밍 + MP4로 영구 변환 (개별/일괄, SSE 진행률)
  • PNG → JPG 변환 — 업로드 시 자동(설정 토글, 기본 ON, 흰 배경 합성) + 카드/일괄 수동 변환(POST /api/convert-image)
  • 움짤 → animated WebP 변환 — GIF·짧은 동영상을 libwebp로 영구 변환(SSE, audio strip + warning), 움짤 탭 한정 일괄 버튼
  • 라이트박스 내 삭제 — 원본 보기 중 🗑 버튼 또는 Delete 키로 즉시 삭제(이미지는 다음 항목으로, 동영상은 닫고 새로고침)

URL 가져오기

  • 여러 URL 동시 입력 → 서버가 순차 다운로드 + 디스크 스트리밍 저장
  • 이미지/동영상/음악 + HLS(.m3u8) 지원 (최고 품질 variant 자동 선택, ffmpeg remux)
  • Content-Type 기반 확장자 결정, 충돌 시 _1 자동 리네임
  • SSE 실시간 진행률, 부분 실패 허용
  • 새로고침/탭 재오픈 후 활성 잡 자동 복원, 개별 URL/배치 취소 + 종료 잡 dismiss

탐색 UX

  • 정렬·타입 필터·이름 검색 툴바 (URL 상태 동기화)
  • 빈 영역 드래그 rubber-band 영역 선택 (데스크톱, modifier로 추가 선택)
  • "움짤" 필터: GIF/WebP + 짧고 작은 동영상 (≤ 30s, ≤ 50 MiB)
  • 움짤 카드 hover/IntersectionObserver 자동재생 — 평시 정적 첫 프레임으로 부담 완화
  • 파일 용량 요약 (breadcrumb 우측) + 개별 size badge

다운로드 설정

  • 헤더 ⚙ 버튼 → 최대 다운로드 크기 / 타임아웃 + PNG → JPG 자동 변환 토글
  • <dataDir>/.config/settings.json에 영속화

실행

Docker Compose (권장)

docker compose up -d
  • 포트: http://localhost:8080
  • 데이터: Docker named volume media (→ 컨테이너 /data)
  • 볼륨 위치를 로컬 디렉터리로 바꾸려면 docker-compose.ymlvolumes 매핑을 ./data:/data 등으로 수정

로컬 개발 (Go 직접 실행)

# ffmpeg 설치 필요 (썸네일 / 스트림 / 변환)
go run ./cmd/server

환경변수:

변수 기본값 설명
DATA_DIR /data 미디어 파일 저장 루트
WEB_DIR web 정적 프론트엔드 경로

API 요약

Method Path 설명
GET /api/browse?path= 디렉터리 목록
GET /api/tree 폴더 트리 (사이드바)
GET /api/stream?path= Range 스트리밍 (TS는 실시간 remux)
GET /api/thumb?path= 섬네일 (이미지/동영상)
POST /api/upload?path= 멀티파트 업로드
POST /api/folder?path= 폴더 생성
PATCH /api/folder?path= 폴더 rename({name}) 또는 이동({to})
DELETE /api/folder?path= 폴더 재귀 삭제
PATCH /api/file?path= 파일 rename({name}) 또는 이동({to})
DELETE /api/file?path= 파일 삭제
POST /api/import-url?path= URL/HLS 다운로드 시작 (SSE 응답에 register+queued+...)
GET /api/import-url/jobs 활성·이력 잡 목록 (페이지 새로고침 시 복원용)
GET /api/import-url/jobs/{id}/events 잡에 라이브 SSE 재구독 (snapshot+events)
POST /api/import-url/jobs/{id}/cancel 배치 전체 취소 (?index=N이면 개별 URL)
DELETE /api/import-url/jobs/{id} 종료된 잡을 history에서 제거 (활성이면 409)
DELETE /api/import-url/jobs?status=finished 종료된 잡 일괄 정리
POST /api/convert TS → MP4 영구 변환 (SSE)
POST /api/convert-image PNG → JPG 동기 변환 (단건/배치)
POST /api/convert-webp 움짤(GIF / 짧은 동영상) → animated WebP 변환 (SSE)
GET/PATCH /api/settings 다운로드 설정 + PNG 자동 변환 토글

mutating 라우트(POST·PATCH·DELETE)는 모두 Origin == Host 또는 Sec-Fetch-Site allowlist를 통과해야 한다. 거부 시 403 cross_origin (상세는 SPEC.md §5.3).

본문 크기 상한: multipart 업로드 100 GiB / JSON body 64 KiB. 초과 시 413 too_large (http.MaxBytesReader, 상세는 SPEC.md §5 각 엔드포인트 4xx 표 / §9).

스키마 상세는 SPEC.md §5.


구조

cmd/server/        엔트리포인트 (net/http + graceful shutdown)
internal/
  handler/        HTTP 엔드포인트
  media/          타입/MIME 판별 + 파일/폴더 이동(MoveFile/MoveDir)
  thumb/          이미지·동영상 썸네일 생성 (ffmpeg + animated WebP 폴백)
  urlfetch/       URL/HLS 다운로드 (SSE 진행 스트림)
  convert/        TS → MP4 + 움짤 → animated WebP ffmpeg 러너
  imageconv/      PNG → JPG 변환 (흰 배경 합성, atomic write)
  importjob/      잡 라이프사이클·이벤트 채널·Registry (인메모리)
  settings/       다운로드 설정 영속화
web/              index.html + style.css + main.js + 17개 ES module

테스트

go test ./...

핸들러·썸네일·urlfetch·convert 계층에 단위/통합 테스트 존재. 일부 테스트는 ffmpeg/ffprobe 바이너리를 요구.


기술 스택

  • Backend: Go 1.26, net/http stdlib, github.com/disintegration/imaging
  • Transcoding/Probe: ffmpeg, ffprobe (alpine apk)
  • WebP 도구: libwebp-tools (alpine apk — webpmux + dwebp). animated WebP 첫 프레임 추출에 사용
  • Frontend: Vanilla HTML/CSS/JS (의존성 없음, ES module 17개)
  • Container: Docker multi-stage build (alpine:3.19 런타임)

릴리즈 노트

0.0.2 — 이미지/움짤 변환 + 선택 UX

  • PNG → JPG 변환 (Phase 25): 업로드 시 자동(설정 토글, 기본 ON, 흰 배경 합성) + 카드/일괄 수동 변환(POST /api/convert-image). 새 패키지 internal/imageconv. PNG decompression bomb 방어(DecodeConfig 픽셀 cap).
  • 움짤 → animated WebP 변환 (Phase 29): GIF·짧은 동영상을 libwebp로 영구 변환(SSE 진행, audio strip + warning). POST /api/convert-webp + 모달/카드/일괄 버튼.
  • 선택 UX (Phase 26-27): 카드/행 체크박스 + 빈 영역 rubber-band 드래그로 visible 항목 일괄 선택. selection-aware PNG/움짤 일괄 변환, 사이드바 폴더로 한 번에 이동.
  • 라이트박스 내 삭제 (Phase 28): 원본 보기 중 🗑 버튼 또는 Delete 키. 이미지는 다음 항목으로, 동영상은 닫고 새로고침.
  • 움짤 자동재생 (Phase 30): 카드 hover / IntersectionObserver로 src 토글, 움짤 탭 카드 240px. animated WebP thumb 첫 프레임 폴백(webpmux + dwebp).
  • Batch cap 상향: URL import / TS convert / PNG convert 모두 50 → 500.
  • 운영 안정성: upload/JSON body MaxBytesReader 캡, 외부 도구(webpmux/dwebp/ffprobe) timeout + stderr 캡처, import job 워커 panic recovery, createFolder TOCTOU 제거, browse 사이드카 stat 최적화(ReadDir 1회 + map lookup).
  • Module path: 외부 import 대상이 아닌 단일 바이너리 가정으로 file_server로 단축.
  • Breaking changes: 없음.

0.0.1 — 폴더 CRUD 완성판

  • 폴더 이동 백엔드: media.MoveDir + PATCH /api/folder body 분기({name} rename | {to} move). 자기 자신·자손 거부, 충돌 시 409 (자동 suffix 없음 — rename과 일관). EXDEV는 500 (단일 볼륨 전제).
  • 사이드바 트리 폴더 운영: 노드 hover 시 ✎ rename · 🗑 삭제 노출. "+ 새 폴더" 버튼이 메인 헤더에서 사이드바 헤더로 이전 (모바일 드로어에서는 햄버거 → 드로어 열기 후 사용).
  • 폴더 DnD: 사이드바 트리 노드 또는 메인 리스트 폴더 행을 다른 트리 노드/breadcrumb 위로 끌어 놓아 이동. 자기 자신/자손으로 드래그하면 drop 거부.
  • Breaking changes: 없음. 기존 API/UI 동작 그대로, 새 폴더 이동 경로만 추가.

About

Media Manager. 미디어 관리 서버. 내가 쓰려고 만듬

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors