Skip to content

v0.4.0 — P0 안정성 강화 + 추천 개편 + 코드 품질 대규모 개선

Choose a tag to compare

@bigpie1367 bigpie1367 released this 24 Mar 03:57
· 37 commits to main since this release
ce009b0

brainstream v0.4.0

P0 안정성 강화, 추천 시스템 개편, 페이지네이션/검색, 대규모 코드 품질 개선을 포함한 메이저 릴리즈.


What's Changed

New Features

  • P0 안정성 강화: graceful shutdown (try/finally + worker join 30s), yt-dlp 타임아웃 (메타 60s/다운로드 600s), API rate limiting (슬라이딩 윈도우), SSE 큐 TTL (30분 자동 정리), 로그 로테이션 (50MB × 5)
  • 추천 시스템 개편: CF 추천 offset 페이지네이션(80%) + LB Radio 탐색(20%) 이중 소스 구조. CF 모델 갱신 감지, CF 풀 소진 시 Radio 폴백
  • 파이프라인 주기 설정: GET/PUT /api/settings/pipeline-interval + UI 드롭다운. settings 테이블 동적 주기 적용
  • 페이지네이션 + 검색: GET /api/downloads?limit=&offset=&search= 페이지네이션 API + 수동 다운로드 중복 체크 (artist+track 기준 409)
  • 무한 스크롤 + 검색 UI: IntersectionObserver 기반 무한 스크롤, 실시간 검색 입력
  • /health 엔드포인트: 컨테이너 liveness probe 지원
  • Multi-worktree Compose 격리: worktree별 고유 프로젝트명 + 포트 자동 배정

Bug Fixes

  • FLAC 태그 리스트 형식 통일: scalar → list 할당으로 Opus/OGG와 일관성 확보
  • mark_done album NULL 덮어쓰기: COALESCE로 기존 album 보존
  • Lucene 특수문자 전체 이스케이프: &&, || 등 다문자 연산자 포함 완전 처리
  • MB 아티스트명 추출: 첫 번째 결과 대신 선택된 recording의 artist-credit 사용
  • auth salt 보안: random.choices → secrets.token_hex
  • Rate limiter 메모리 누수: 주기적 정리 + safe dict iteration
  • auto-refresh 셀렉터 버그: #history-table → #section-history (DOM에 없는 셀렉터로 자동 갱신 미작동)
  • rematch_apply 파일 덮어쓰기: 이동 전 os.path.exists 충돌 체크 추가 (409)
  • _write_single_tag 예외 삼킴: raise하도록 변경, API 엔드포인트가 태그 실패 감지 가능
  • mark_pending_if_not_duplicate 경쟁 조건: INSERT ... WHERE NOT EXISTS 단일 문으로 atomic 처리
  • 재시작 시 이중 enqueue: is_downloaded()가 pending/downloading도 필터
  • get_retryable source 누락: manual 실패 잡이 source='listenbrainz'로 재시도되던 버그 수정
  • stale SSE 응답 race condition: requestSeq 기반 무효화
  • Healthcheck 포트: 8080 → 8000 (컨테이너 내부 포트)
  • tagger KeyError: meta["artist"] → meta.get("artist")
  • logger dirname 빈 문자열: guard 추가

Refactoring

  • musicbrainz.py 모듈 분리: MB API 상수, lookup_recording, mb_search_recording, mb_album_from_recording_id를 공유 모듈로 추출
  • tagger 포맷 디스패치 딕셔너리: ~400줄 중복 제거, _FORMAT_OPENER/_FORMAT_KEYS 구조
  • jobs.py 분리: _run_download_job을 api.py에서 src/jobs.py로 추출
  • move_to_music_dir 헬퍼: 파일 이동 로직 통합 (resolve_dir + case-insensitive 매칭)
  • src/utils/fs.py: sanitize 함수 통합
  • async httpx 마이그레이션: rematch 엔드포인트 blocking requests → async httpx
  • httpx.AsyncClient 공유: FastAPI lifespan 기반 싱글톤

Technical Details

모듈 주요 변경
src/main.py CF offset 진행 + LB Radio 이중 소스, CF 모델 갱신 감지, daemon worker thread
src/state.py settings 테이블, get_downloads_page, mark_pending_if_not_duplicate (atomic), is_downloaded 확장
src/api.py pipeline interval API, 페이지네이션, 중복 체크 409, rematch 파일 충돌 체크, rate limiting
src/worker.py SSE 큐 TTL, touch_sse_queue, _cleanup_expired_queues
src/pipeline/musicbrainz.py 신규 — 공유 MB API 클라이언트 (4단계 검색 + Lucene 이스케이프)
src/pipeline/tagger.py 포맷 디스패치 딕셔너리, _write_single_tag 예외 전파
src/pipeline/listenbrainz.py fetch_user_top_artists, fetch_lb_radio, offset 파라미터
src/pipeline/downloader.py yt-dlp 타임아웃, _run_with_timeout
src/jobs.py 신규 — run_download_job 분리
src/utils/fs.py 신규 — sanitize_path_component, resolve_dir, move_to_music_dir
src/static/index.html 무한 스크롤, 검색, pipeline interval 드롭다운, auto-refresh 수정
restart_local_docker.sh worktree 격리, 서브커맨드 (restart/stop/logs/status/info)

Full Changelog: v0.3.0...v0.4.0