music-lab: 라이브러리 파일시스템 동기화 + v2 파일명 중복 수정

- GET /api/music/library 호출 시 디스크 .mp3 파일과 DB 자동 동기화
  - 디스크에 없는 트랙 → DB에서 삭제
  - DB에 없는 .mp3 → 새 트랙으로 자동 등록
- NAS에서 파일명 변경 시 웹에 자동 반영
- _v2_v2 파일명 중복 버그 수정

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 13:56:42 +09:00
parent 33a011a086
commit d2606d7317

View File

@@ -171,10 +171,52 @@ class TrackCreate(BaseModel):
@app.get("/api/music/library") @app.get("/api/music/library")
def list_library(): def list_library():
"""저장된 트랙 목록 전체 조회 (생성일 내림차순)""" """저장된 트랙 목록 전체 조회 (생성일 내림차순). 파일시스템과 자동 동기화."""
_sync_library_with_disk()
return {"tracks": get_all_tracks()} return {"tracks": get_all_tracks()}
def _sync_library_with_disk():
"""파일시스템의 .mp3 파일과 DB를 동기화.
- 디스크에 없는 트랙 → DB에서 삭제
- DB에 없는 .mp3 파일 → 새 트랙으로 추가
"""
tracks = get_all_tracks()
media_base = os.getenv("MUSIC_MEDIA_BASE", "/media/music")
# 디스크의 .mp3 파일 목록
disk_files = set()
try:
for f in os.listdir(MUSIC_DATA_DIR):
if f.lower().endswith(".mp3"):
disk_files.add(f)
except OSError:
return # 디렉토리 접근 불가 시 동기화 스킵
# DB 트랙의 파일명 매핑
db_filenames = {} # filename → track
for t in tracks:
if t.get("audio_url"):
fname = t["audio_url"].split("/")[-1]
db_filenames[fname] = t
# DB에는 있지만 디스크에 없는 → 삭제
for fname, t in db_filenames.items():
if fname not in disk_files:
delete_track(t["id"])
# 디스크에는 있지만 DB에 없는 → 추가
for f in disk_files:
if f not in db_filenames:
title = os.path.splitext(f)[0].replace("-", " ").replace("_", " ")
add_track({
"title": title,
"audio_url": f"{media_base}/{f}",
"file_path": os.path.join(MUSIC_DATA_DIR, f),
"provider": "suno",
})
@app.post("/api/music/library", status_code=201) @app.post("/api/music/library", status_code=201)
def save_to_library(req: TrackCreate): def save_to_library(req: TrackCreate):
"""트랙 수동 추가 (외부 파일 등록 또는 프론트 직접 저장용)""" """트랙 수동 추가 (외부 파일 등록 또는 프론트 직접 저장용)"""